001: /*
002: * (C) Copyright 2000 - 2005 Nabh Information Systems, Inc.
003: *
004: * This program is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU General Public License
006: * as published by the Free Software Foundation; either version 2
007: * of the License, or (at your option) any later version.
008: *
009: * This program has been modified by Nabh Information Systems, Inc.
010: * (http://www.nabh.com) to conform to Stringbeans compliant bridge.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * ==================================================================
022: *
023: * Copyright 2000-2004 The Apache Software Foundation.
024: *
025: * Licensed under the Apache License, Version 2.0 (the "License");
026: * you may not use this file except in compliance with the License.
027: * You may obtain a copy of the License at
028: *
029: * http://www.apache.org/licenses/LICENSE-2.0
030: *
031: * Unless required by applicable law or agreed to in writing, software
032: * distributed under the License is distributed on an "AS IS" BASIS,
033: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
034: * See the License for the specific language governing permissions and
035: * limitations under the License.
036: */
037: package com.nabhinc.portlet.strutsbridge;
038:
039: import java.io.IOException;
040: import java.io.PrintWriter;
041:
042: import javax.portlet.ActionRequest;
043: import javax.portlet.ActionResponse;
044: import javax.portlet.GenericPortlet;
045: import javax.portlet.PortletConfig;
046: import javax.portlet.PortletException;
047: import javax.portlet.PortletRequest;
048: import javax.portlet.PortletResponse;
049: import javax.portlet.RenderRequest;
050: import javax.portlet.RenderResponse;
051: import javax.servlet.RequestDispatcher;
052: import javax.servlet.ServletContext;
053: import javax.servlet.ServletException;
054: import javax.servlet.http.HttpServletRequest;
055: import javax.servlet.http.HttpServletResponse;
056: import javax.servlet.http.HttpSession;
057:
058: import org.apache.commons.logging.Log;
059: import org.apache.commons.logging.LogFactory;
060: import org.apache.portals.bridges.common.ServletContextProvider;
061: import org.apache.portals.bridges.struts.PortletServletRequestWrapper;
062: import org.apache.portals.bridges.struts.StrutsPortletErrorContext;
063: import org.apache.portals.bridges.struts.StrutsPortletURL;
064: import org.apache.portals.bridges.struts.config.StrutsPortletConfig;
065: import org.apache.portals.bridges.struts.util.EmptyHttpServletResponseWrapper;
066:
067: import com.nabhinc.portal.container.HttpServletResponseStringbeansWrapper;
068: import com.nabhinc.portal.container.PortletResponseImpl;
069:
070: /**
071: * StrutsPortlet
072: *
073: * @author <a href="mailto:ate@douma.nu">Ate Douma</a>
074: *
075: * @since 2.5
076: */
077: public class StrutsPortlet extends GenericPortlet {
078: /**
079: * Name of class implementing {@link ServletContextProvider}
080: */
081: public static final String PARAM_SERVLET_CONTEXT_PROVIDER = "ServletContextProvider";
082: /**
083: * Name of portlet preference for Struts Portlet Config Location
084: */
085: public static final String STRUTS_PORTLET_CONFIG_LOCATION = "StrutsPortletConfigLocation";
086: /**
087: * Name of portlet preference for Action page
088: */
089: public static final String PARAM_ACTION_PAGE = "ActionPage";
090: /**
091: * Name of portlet preference for Custom page
092: */
093: public static final String PARAM_CUSTOM_PAGE = "CustomPage";
094: /**
095: * Name of portlet preference for Edit page
096: */
097: public static final String PARAM_EDIT_PAGE = "EditPage";
098: /**
099: * Name of portlet preference for Edit page
100: */
101: public static final String PARAM_HELP_PAGE = "HelpPage";
102: /**
103: * Name of portlet preference for View page
104: */
105: public static final String PARAM_VIEW_PAGE = "ViewPage";
106: /**
107: * Default URL for the action page.
108: */
109: private String defaultActionPage = null;
110: /**
111: * Default URL for the custom page.
112: */
113: private String defaultCustomPage = null;
114: /**
115: * Default URL for the edit page.
116: */
117: private String defaultEditPage = null;
118: /**
119: * Default URL for the help page.
120: */
121: private String defaultHelpPage = null;
122: /**
123: * Default URL for the view page.
124: */
125: private String defaultViewPage = null;
126: private ServletContextProvider servletContextProvider;
127: private static final Log log = LogFactory
128: .getLog(StrutsPortlet.class);
129: public static final String REQUEST_TYPE = "org.apache.portals.bridges.struts.request_type";
130: public static final String PAGE_URL = "org.apache.portals.bridges.struts.page_url";
131: public static final String ORIGIN_URL = "org.apache.portals.bridges.struts.origin_url";
132: public static final String REDIRECT_PAGE_URL = "org.apache.portals.bridges.struts.redirect_page_url";
133: public static final String REDIRECT_URL = "org.apache.portals.bridges.struts.redirect_url";
134: public static final String RENDER_CONTEXT = "org.apache.portals.bridges.struts.render_context";
135: public static final String ERROR_CONTEXT = "org.apache.portals.bridges.struts.error_context";
136: public static final String PORTLET_NAME = "org.apache.portals.bridges.struts.portlet_name";
137: public static final String STRUTS_PORTLET_CONFIG = "org.apache.portals.bridges.struts.portlet_config";
138: public static final String DEFAULT_STRUTS_PORTLET_CONFIG_LOCATION = "WEB-INF/struts-portlet-config.xml";
139: public static final String ACTION_REQUEST = "ACTION";
140: public static final String VIEW_REQUEST = "VIEW";
141: public static final String CUSTOM_REQUEST = "CUSTOM";
142: public static final String EDIT_REQUEST = "EDIT";
143: public static final String HELP_REQUEST = "HELP";
144:
145: private StrutsPortletConfig strutsPortletConfig;
146:
147: public void init(PortletConfig config) throws PortletException {
148: super .init(config);
149: String contextProviderClassName = getContextProviderClassNameParameter(config);
150: if (contextProviderClassName == null)
151: throw new PortletException("Portlet "
152: + config.getPortletName()
153: + " is incorrectly configured. Init parameter "
154: + PARAM_SERVLET_CONTEXT_PROVIDER + " not specified");
155: if (contextProviderClassName != null) {
156: try {
157: Class clazz = Class.forName(contextProviderClassName);
158: if (clazz != null) {
159: Object obj = clazz.newInstance();
160: if (ServletContextProvider.class.isInstance(obj)) {
161: servletContextProvider = (ServletContextProvider) obj;
162: } else
163: throw new PortletException("class not found");
164: }
165: } catch (Exception e) {
166: if (e instanceof PortletException)
167: throw (PortletException) e;
168: e.printStackTrace();
169: throw new PortletException("Cannot load", e);
170: }
171: }
172: if (servletContextProvider == null)
173: throw new PortletException(
174: "Portlet "
175: + config.getPortletName()
176: + " is incorrectly configured. Invalid init parameter "
177: + PARAM_SERVLET_CONTEXT_PROVIDER
178: + " value " + contextProviderClassName);
179: this .defaultActionPage = getActionPageParameter(config);
180: this .defaultCustomPage = getCustomPageParameter(config);
181: this .defaultEditPage = getEditPageParameter(config);
182: this .defaultViewPage = getViewPageParameter(config);
183: this .defaultHelpPage = getHelpPageParameter(config);
184:
185: if (this .defaultViewPage == null) {
186: // A Struts Portlet is required to have at least the
187: // defaultViewPage
188: // defined!
189: throw new PortletException(
190: "Portlet "
191: + config.getPortletName()
192: + " is incorrectly configured. No default View page is defined.");
193: }
194: if (defaultActionPage == null)
195: defaultActionPage = defaultViewPage;
196: if (defaultCustomPage == null)
197: defaultCustomPage = defaultViewPage;
198: if (defaultHelpPage == null)
199: defaultHelpPage = defaultViewPage;
200: if (defaultEditPage == null)
201: defaultEditPage = defaultViewPage;
202:
203: strutsPortletConfig = new StrutsPortletConfig();
204: String strutsPortletConfigLocation = getStrutsPortletConfigLocationParameter(config);
205: if (strutsPortletConfigLocation == null) {
206: strutsPortletConfigLocation = DEFAULT_STRUTS_PORTLET_CONFIG_LOCATION;
207: }
208: strutsPortletConfig.loadConfig(config.getPortletContext(),
209: strutsPortletConfigLocation);
210: config.getPortletContext().setAttribute(STRUTS_PORTLET_CONFIG,
211: strutsPortletConfig);
212: }
213:
214: protected String getContextProviderClassNameParameter(
215: PortletConfig config) {
216: return config.getInitParameter(PARAM_SERVLET_CONTEXT_PROVIDER);
217: }
218:
219: protected ServletContextProvider getServletContextProvider() {
220: return servletContextProvider;
221: }
222:
223: protected ServletContext getServletContext(GenericPortlet portlet,
224: PortletRequest request, PortletResponse response) {
225: return getServletContextProvider().getServletContext(portlet);
226: }
227:
228: protected HttpServletRequest getHttpServletRequest(
229: GenericPortlet portlet, PortletRequest request,
230: PortletResponse response) {
231: return getServletContextProvider().getHttpServletRequest(
232: portlet, request);
233: }
234:
235: protected HttpServletResponse getHttpServletResponse(
236: GenericPortlet portlet, PortletRequest request,
237: PortletResponse response) {
238: return getServletContextProvider().getHttpServletResponse(
239: portlet, response);
240: }
241:
242: protected String getStrutsPageURL(PortletRequest request) {
243: return request.getParameter(StrutsPortletURL.PAGE);
244: }
245:
246: protected String getStrutsOriginURL(PortletRequest request) {
247: return request.getParameter(StrutsPortletURL.ORIGIN);
248: }
249:
250: protected String getActionPageParameter(PortletConfig config) {
251: return config.getInitParameter(PARAM_ACTION_PAGE);
252: }
253:
254: protected String getCustomPageParameter(PortletConfig config) {
255: return config.getInitParameter(PARAM_CUSTOM_PAGE);
256: }
257:
258: protected String getEditPageParameter(PortletConfig config) {
259: return config.getInitParameter(PARAM_EDIT_PAGE);
260: }
261:
262: protected String getViewPageParameter(PortletConfig config) {
263: return config.getInitParameter(PARAM_VIEW_PAGE);
264: }
265:
266: protected String getHelpPageParameter(PortletConfig config) {
267: return config.getInitParameter(PARAM_HELP_PAGE);
268: }
269:
270: protected String getStrutsPortletConfigLocationParameter(
271: PortletConfig config) {
272: return config.getInitParameter(STRUTS_PORTLET_CONFIG_LOCATION);
273: }
274:
275: public void doEdit(RenderRequest request, RenderResponse response)
276: throws PortletException, IOException {
277: processRequest(request, response, defaultEditPage,
278: StrutsPortlet.EDIT_REQUEST);
279: }
280:
281: public void doHelp(RenderRequest request, RenderResponse response)
282: throws PortletException, IOException {
283: processRequest(request, response, defaultHelpPage,
284: StrutsPortlet.HELP_REQUEST);
285: }
286:
287: public void doCustom(RenderRequest request, RenderResponse response)
288: throws PortletException, IOException {
289: processRequest(request, response, defaultCustomPage,
290: StrutsPortlet.CUSTOM_REQUEST);
291: }
292:
293: public void doView(RenderRequest request, RenderResponse response)
294: throws PortletException, IOException {
295: processRequest(request, response, defaultViewPage,
296: StrutsPortlet.VIEW_REQUEST);
297: }
298:
299: public void processAction(ActionRequest request,
300: ActionResponse response) throws PortletException,
301: IOException {
302: processRequest(request, response, defaultActionPage,
303: StrutsPortlet.ACTION_REQUEST);
304: }
305:
306: protected void processRequest(PortletRequest request,
307: PortletResponse response, String defaultPage,
308: String requestType) throws PortletException, IOException {
309: boolean actionRequest = (request instanceof ActionRequest);
310: ServletContext servletContext = getServletContext(this ,
311: request, response);
312: HttpServletRequest req = getHttpServletRequest(this , request,
313: response);
314: HttpServletResponse res = null;
315: if (actionRequest) {
316: res = new EmptyHttpServletResponseWrapper(
317: ((PortletResponseImpl) response)
318: .getHttpServletResponse());
319: } else {
320: res = getHttpServletResponse(this , request, response);
321: }
322: HttpSession session = req.getSession();
323: String portletName = this .getPortletConfig().getPortletName();
324: req.setAttribute(PORTLET_NAME, portletName);
325:
326: try {
327: StrutsPortletErrorContext errorContext = (StrutsPortletErrorContext) req
328: .getSession().getAttribute(
329: StrutsPortlet.ERROR_CONTEXT + "_"
330: + portletName);
331: if (errorContext != null) {
332: if (!actionRequest) {
333: req.getSession().removeAttribute(
334: StrutsPortlet.ERROR_CONTEXT + "_"
335: + portletName);
336: renderError(res, errorContext);
337: }
338: return;
339: }
340:
341: String keepRenderAttributes = null;
342:
343: if (!actionRequest) {
344: keepRenderAttributes = request
345: .getParameter(StrutsPortletURL.KEEP_RENDER_ATTRIBUTES);
346: }
347: if (keepRenderAttributes == null) {
348: strutsPortletConfig.getRenderContextAttributes()
349: .clearAttributes(session);
350: } else {
351: strutsPortletConfig.getRenderContextAttributes()
352: .restoreAttributes(req);
353: }
354:
355: String path = null;
356: String pageURL = getStrutsPageURL(request);
357:
358: if (pageURL == null)
359: path = defaultPage;
360: else {
361: path = pageURL;
362: }
363:
364: if (log.isDebugEnabled())
365: log.debug("process path: " + path + ", requestType: "
366: + requestType);
367:
368: RequestDispatcher rd = servletContext
369: .getRequestDispatcher(path);
370: if (rd != null) {
371:
372: if (actionRequest) {
373: // http://issues.apache.org/jira/browse/PB-2:
374: // provide servlet access to the Portlet components even from
375: // an actionRequest in extension to the JSR-168 requirement
376: // PLT.16.3.2 which (currently) only covers renderRequest
377: // servlet inclusion.
378: if (req.getAttribute("javax.portlet.config") == null) {
379: req.setAttribute("javax.portlet.config",
380: getPortletConfig());
381: }
382: if (req.getAttribute("javax.portlet.request") == null) {
383: req.setAttribute("javax.portlet.request",
384: request);
385: }
386: if (req.getAttribute("javax.portlet.response") == null) {
387: req.setAttribute("javax.portlet.response",
388: response);
389: }
390: String origin = getStrutsOriginURL(request);
391: if (origin == null) {
392: origin = defaultPage;
393: }
394: request.setAttribute(StrutsPortlet.ORIGIN_URL,
395: origin);
396: }
397: if (path != null)
398: req.setAttribute(StrutsPortlet.PAGE_URL, path);
399: req.setAttribute(StrutsPortlet.REQUEST_TYPE,
400: requestType);
401: try {
402: rd.include(new PortletServletRequestWrapper(
403: servletContext, req), res);
404: } catch (ServletException e) {
405: if (log.isErrorEnabled())
406: log.error("Include exception", e);
407: errorContext = new StrutsPortletErrorContext();
408: errorContext.setError(e);
409: //req.setAttribute(StrutsPortlet.ERROR_CONTEXT + "_" + portletName, errorContext);
410: req.setAttribute(StrutsPortlet.ERROR_CONTEXT,
411: errorContext);
412: if (!actionRequest)
413: renderError(res, errorContext);
414: }
415: if (actionRequest) {
416: String renderURL;
417: if (req.getAttribute(StrutsPortlet.ERROR_CONTEXT) != null) {
418: pageURL = StrutsPortletURL.getOriginURL(req); //request.getParameter(StrutsPortletURL.ORIGIN);
419: if (pageURL != null)
420: ((ActionResponse) response)
421: .setRenderParameter(
422: StrutsPortletURL.PAGE,
423: pageURL);
424: if (log.isDebugEnabled())
425: log.debug("action render error context");
426: try {
427: req
428: .getSession(true)
429: .setAttribute(
430: StrutsPortlet.ERROR_CONTEXT
431: + "_" + portletName,
432: req
433: .getAttribute(StrutsPortlet.ERROR_CONTEXT));
434: } catch (IllegalStateException ise) {
435: // catch Session already invalidated exception
436: // There isn't much we can do here other than
437: // redirecting the user to the start page
438: }
439: } else {
440: if ((renderURL = (String) req
441: .getAttribute(StrutsPortlet.REDIRECT_URL)) != null) {
442: if (log.isDebugEnabled())
443: log.debug("action send redirect: "
444: + renderURL);
445: ((ActionResponse) response)
446: .sendRedirect(renderURL);
447: } else {
448: strutsPortletConfig
449: .getRenderContextAttributes()
450: .saveAttributes(req);
451: ((ActionResponse) response)
452: .setRenderParameter(
453: StrutsPortletURL.KEEP_RENDER_ATTRIBUTES,
454: "1");
455:
456: if ((renderURL = (String) req
457: .getAttribute(StrutsPortlet.REDIRECT_PAGE_URL)) != null) {
458: if (log.isDebugEnabled())
459: log
460: .debug("action render redirected page: "
461: + renderURL);
462: pageURL = renderURL;
463: }
464: if (pageURL != null) {
465: if (renderURL == null
466: && log.isWarnEnabled())
467: log
468: .warn("Warning: Using the original action URL for render URL: "
469: + pageURL
470: + ".\nA redirect should have been issued.");
471: ((ActionResponse) response)
472: .setRenderParameter(
473: StrutsPortletURL.PAGE,
474: pageURL);
475: }
476: }
477: }
478: }
479: }
480: } catch (IOException e) {
481: if (log.isErrorEnabled())
482: log.error("unexpected", e);
483: throw e;
484: } finally {
485: if (res instanceof HttpServletResponseStringbeansWrapper) {
486: ((HttpServletResponseStringbeansWrapper) res)
487: .setRenderResponse(null);
488: }
489: }
490: }
491:
492: protected void renderError(HttpServletResponse response,
493: StrutsPortletErrorContext errorContext) throws IOException {
494: PrintWriter writer = response.getWriter();
495: writer.println("<hr/><h2>Error</h2>");
496: writer.println("<table border='1'>");
497: if (errorContext.getErrorCode() != 0)
498: writer
499: .println("<tr><td valign='top'><b>Error Code</b></td><td>"
500: + errorContext.getErrorCode()
501: + "</td></tr>");
502: if (errorContext.getErrorMessage() != null)
503: writer
504: .println("<tr><td valign='top'><b>Error Message</b></td><td>"
505: + errorContext.getErrorMessage()
506: + "</td></tr>");
507: if (errorContext.getError() != null) {
508: Throwable e = errorContext.getError();
509: if (e instanceof ServletException
510: && ((ServletException) e).getRootCause() != null)
511: e = ((ServletException) e).getRootCause();
512: writer.print("<tr><td valign='top'><b>Error</b></td><td>"
513: + e.getMessage() + "</td></tr>");
514: writer
515: .print("<tr><td valign='top'><b>Error Type</b></td><td>"
516: + e.getClass().getName() + "</td></tr>");
517: writer
518: .print("<tr><td valign='top'><b>Stacktrace</b></td><td>");
519: StackTraceElement[] elements = e.getStackTrace();
520: StringBuffer buf = new StringBuffer();
521: for (int i = 0; i < elements.length; i++)
522: buf.append(" " + elements[i].toString() + "<br>");
523: writer.print(buf.toString());
524: writer.println("</td></tr>");
525: }
526: writer.println("</table>");
527: }
528: }
|