001: /*
002: * (C) Copyright 2000 - 2006 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 is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: *
018: */
019: package com.nabhinc.portal.model;
020:
021: import java.io.IOException;
022: import java.io.UnsupportedEncodingException;
023: import java.net.URLEncoder;
024: import java.util.Hashtable;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Locale;
028: import java.util.Map;
029: import java.util.Set;
030: import java.util.Vector;
031:
032: import javax.portlet.PortletException;
033: import javax.portlet.PortletMode;
034: import javax.portlet.PortletModeException;
035: import javax.portlet.PortletPreferences;
036: import javax.portlet.PortletSecurityException;
037: import javax.portlet.RenderRequest;
038: import javax.portlet.UnavailableException;
039: import javax.portlet.WindowState;
040: import javax.portlet.WindowStateException;
041: import javax.servlet.RequestDispatcher;
042: import javax.servlet.ServletContext;
043: import javax.servlet.ServletException;
044: import javax.servlet.http.HttpServletRequest;
045: import javax.servlet.http.HttpSession;
046: import javax.xml.bind.Unmarshaller;
047: import javax.xml.bind.annotation.XmlAttribute;
048: import javax.xml.bind.annotation.XmlElementRef;
049: import javax.xml.bind.annotation.XmlRootElement;
050: import javax.xml.bind.annotation.XmlTransient;
051:
052: import org.apache.commons.logging.Log;
053: import org.apache.commons.logging.LogFactory;
054:
055: import com.nabhinc.portal.api.PortalInformationStoreLocator;
056: import com.nabhinc.portal.container.ActionRequestImpl;
057: import com.nabhinc.portal.container.ActionResponseImpl;
058: import com.nabhinc.portal.container.PortalInterface;
059: import com.nabhinc.portal.container.PortletPreferencesImpl;
060: import com.nabhinc.portal.container.PortletRequestImpl;
061: import com.nabhinc.portal.container.PreferencesStore;
062: import com.nabhinc.portal.container.RenderRequestImpl;
063: import com.nabhinc.portal.container.RenderResponseImpl;
064: import com.nabhinc.portal.core.CacheControl;
065: import com.nabhinc.portal.core.NavigationState;
066: import com.nabhinc.portal.core.PortalConstants;
067: import com.nabhinc.portal.core.PortalServlet;
068: import com.nabhinc.portal.core.PortalUtil;
069: import com.nabhinc.portal.core.PortletConfigInfo;
070: import com.nabhinc.portal.core.SessionCache;
071: import com.nabhinc.util.StringUtil;
072:
073: /**
074: *
075: *
076: * @author Padmanabh Dabke
077: * (c) 2006 Nabh Information Systems, Inc. All Rights Reserved.
078: */
079: @XmlRootElement(name="portlet-window")
080: public class PortletWindow extends BaseRenderable implements
081: Renderable, PortalInterface, PreferencesStore {
082:
083: private transient Log logger = LogFactory.getLog(this .getClass());
084:
085: /**
086: * Name of the portlet associated with this PortletWindow
087: */
088: @XmlAttribute(name="name")
089: private String portletName = null;
090:
091: @XmlAttribute(name="maximized")
092: private boolean maximized = false;
093:
094: @XmlAttribute(name="minimized")
095: private boolean minimized = false;
096:
097: @XmlAttribute(name="height")
098: private String height = "200px";
099:
100: @XmlAttribute(name="width")
101: private String width = "200px";
102:
103: @XmlAttribute(name="top")
104: private String top = "200px";
105:
106: @XmlAttribute(name="left")
107: private String left = "200px";
108:
109: @XmlAttribute(name="zindex")
110: private int zindex = 900;
111:
112: @XmlElementRef
113: private PortletWindowConfig windowConfig = null;
114: /**
115: * Associated portlet configuration
116: */
117: private transient PortletConfigInfo configInfo = null;
118:
119: public PortletWindow() {
120: }
121:
122: public PortletWindow(PortalPage parent, String pName) {
123: super (parent);
124: setName(pName);
125: }
126:
127: @XmlTransient
128: public PortletWindowConfig getPortletWindowConfig() {
129: return this .windowConfig;
130: }
131:
132: public void setPortletWindowConfig(PortletWindowConfig c) {
133: this .windowConfig = c;
134: }
135:
136: @XmlTransient
137: public String getName() {
138: return this .portletName;
139: }
140:
141: public void setName(String pName) {
142: this .portletName = pName;
143: this .configInfo = PortalServlet.getInstance()
144: .getPortletConfigInfo(pName);
145: }
146:
147: @XmlTransient
148: public boolean isMaximized() {
149: return this .maximized;
150: }
151:
152: public void setMaximized(boolean flag) {
153: this .maximized = flag;
154: }
155:
156: @XmlTransient
157: public boolean isMinimized() {
158: return this .minimized;
159: }
160:
161: public void setMinimized(boolean flag) {
162: this .minimized = flag;
163: }
164:
165: @XmlTransient
166: public String getHeight() {
167: return height;
168: }
169:
170: public void setHeight(String height) {
171: this .height = height;
172: }
173:
174: @XmlTransient
175: public String getLeft() {
176: return left;
177: }
178:
179: public void setLeft(String left) {
180: this .left = left;
181: }
182:
183: @XmlTransient
184: public String getTop() {
185: return top;
186: }
187:
188: public void setTop(String top) {
189: this .top = top;
190: }
191:
192: @XmlTransient
193: public String getWidth() {
194: return width;
195: }
196:
197: public void setWidth(String width) {
198: this .width = width;
199: }
200:
201: @XmlTransient
202: public int getZindex() {
203: return zindex;
204: }
205:
206: public void setZindex(int zindex) {
207: this .zindex = zindex;
208: }
209:
210: public String getDisplayName(RenderRequest request) {
211: String dName = configInfo.getPortletDisplayName(request);
212: if (dName == null)
213: return this .portletName;
214: return dName;
215:
216: }
217:
218: public void store(PortletPreferencesImpl prefs,
219: HttpServletRequest request) throws IOException {
220: if (request.getRemoteUser() == null)
221: return;
222: Hashtable<String, PortletPreferencesImpl.PrefInfo> prefTable = prefs
223: .getUserPreferences();
224: if (prefTable == null || prefTable.size() == 0)
225: return;
226:
227: SessionCache sCache = (SessionCache) request.getSession()
228: .getAttribute(PortalConstants.SESSION_CACHE_ATTRIBUTE);
229: UserPreferences uprefs = sCache.userPrefs;
230: if (uprefs == null) {
231: uprefs = new UserPreferences();
232: uprefs.setName(request.getRemoteUser());
233: sCache.userPrefs = uprefs;
234: }
235: UserPreferences.PortletPreference pref = new UserPreferences.PortletPreference();
236: pref.portletWindowId = this .getId();
237: Iterator<Map.Entry<String, PortletPreferencesImpl.PrefInfo>> entries = prefTable
238: .entrySet().iterator();
239: while (entries.hasNext()) {
240: Map.Entry<String, PortletPreferencesImpl.PrefInfo> entry = entries
241: .next();
242: pref.prefList
243: .add(new UserPreferences.PortletPreferenceEntry(
244: entry.getKey(), entry.getValue().value));
245:
246: }
247: uprefs.addPortletPreference(pref);
248: PortalInformationStoreLocator.getPortalInformationStore()
249: .saveUserPreferences(uprefs);
250:
251: }
252:
253: private void render(RenderRequestImpl renderRequest,
254: RenderResponseImpl renderResponse,
255: HttpServletRequest request) throws PortletException,
256: IOException {
257: String servletURI = configInfo.servletURI;
258: if (servletURI == null)
259: servletURI = PortalConstants.DEFAULT_PORTLET_SERVLET_URI;
260:
261: renderRequest.setAttribute(
262: PortalConstants.PORTLET_CONFIG_ATTRIB,
263: configInfo.config);
264:
265: if (configInfo.contextPath == null) {
266: configInfo.portlet.render(renderRequest, renderResponse);
267: } else {
268: renderRequest.setAttribute(
269: PortalConstants.METHOD_ID_ATTRIB,
270: PortalConstants.METHOD_RENDER);
271: renderRequest.setAttribute(
272: PortalConstants.PORTLET_NAME_ATTRIB,
273: this .portletName);
274: renderRequest.setContextPath(configInfo.contextPath);
275:
276: try {
277: RequestDispatcher dispatcher = request.getSession()
278: .getServletContext().getContext(
279: configInfo.contextPath)
280: .getRequestDispatcher(servletURI);
281: dispatcher.include(request, renderResponse
282: .getHttpServletResponse());
283: } catch (javax.servlet.ServletException e) {
284: if (e.getRootCause() != null) {
285: if (e.getRootCause() instanceof PortletException) {
286: throw (PortletException) e.getRootCause();
287: }
288: throw new PortletException(e.getRootCause());
289: }
290: throw new PortletException(e);
291:
292: } finally {
293: renderRequest
294: .removeAttribute(PortalConstants.METHOD_ID_ATTRIB);
295: }
296:
297: }
298:
299: }
300:
301: public void processAction(ActionRequestImpl actionRequest,
302: ActionResponseImpl actionResponse,
303: HttpServletRequest request) throws PortletException,
304: IOException {
305:
306: String servletURI = configInfo.servletURI;
307: if (servletURI == null)
308: servletURI = PortalConstants.DEFAULT_PORTLET_SERVLET_URI;
309:
310: request.setAttribute(PortalConstants.PORTLET_CONFIG_ATTRIB,
311: configInfo.config);
312:
313: if (configInfo.contextPath == null) {
314: configInfo.portlet.processAction(actionRequest,
315: actionResponse);
316: } else {
317:
318: request.setAttribute(PortalConstants.METHOD_ID_ATTRIB,
319: PortalConstants.METHOD_PROCESS_ACTION);
320: request.setAttribute(PortalConstants.PORTLET_NAME_ATTRIB,
321: this .portletName);
322: actionRequest.setContextPath(configInfo.contextPath);
323: try {
324: RequestDispatcher dispatcher = request.getSession()
325: .getServletContext().getContext(
326: configInfo.contextPath)
327: .getRequestDispatcher(servletURI);
328: dispatcher.include(request, actionResponse
329: .getHttpServletResponse());
330:
331: } catch (javax.servlet.ServletException e) {
332: if (e.getRootCause() != null) {
333: if (e.getRootCause() instanceof PortletException) {
334: throw (PortletException) e.getRootCause();
335: }
336: throw new PortletException(e.getRootCause());
337: }
338:
339: throw new PortletException(e);
340: } finally {
341: request
342: .removeAttribute(PortalConstants.METHOD_ID_ATTRIB);
343: }
344:
345: }
346:
347: }
348:
349: public String getContent(RenderRequestImpl renderRequest,
350: RenderResponseImpl renderResponse,
351: HttpServletRequest request) {
352:
353: try {
354: renderResponse.resetResponse();
355: renderResponse.setTitle(getConfiguredTitle(renderRequest
356: .getLocale()));
357: renderRequest.setPortalInterface(this );
358: renderResponse.setPortalInterface(this );
359: setupNavState(renderRequest, request, renderResponse
360: .isDetached());
361: String currentMode = renderRequest.getPortletMode()
362: .toString().toLowerCase();
363: boolean accessAllowed = PortletAccessController
364: .getInstance().isAccessible(request,
365: this .configInfo, currentMode);
366:
367: if (!accessAllowed) {
368: /*
369: PortalServlet.intercept(request, this,
370: Interceptor.ACCESS_DENIED_NOT_PERMISSIONED);
371: */
372: return "You do not have permission to access this portlet.";
373:
374: }
375: } catch (PortletModeException e) {
376: return "Access denied.";
377: } catch (Exception ex) {
378: /*
379: PortalServlet.intercept(request, this,
380: Interceptor.ACCESS_FAILED_ACCESS_CHECK_EXCEPTION);
381: */
382: this .logger.error(
383: "Exception during access control check for portlet "
384: + portletName, ex);
385: return "There was an exception during access control check.";
386: }
387:
388: // Check if portlet is unavailable
389: if (configInfo.loadStatus != PortletConfigInfo.PORTLET_STATUS_LOADED) {
390: /*
391: PortalServlet.intercept(request, this,
392: Interceptor.ACCESS_FAILED_PORTLET_NOT_AVAILABLE);
393: */
394: return "This portlet is currently unavailable.";
395: }
396:
397: // Check if the portlet requires secure access
398: if (PortalServlet.getInstance().requiresSecureAccess(
399: this .portletName)
400: && !renderRequest.isSecure()) {
401: /*
402: PortalServlet.intercept(request, this,
403: Interceptor.ACCESS_DENIED_NOT_SECURE);
404: */
405: return "<span class=\"portlet-msg-error\">Unable to display the content of this portlet. "
406: + "<br/>Reason: requires secure connection.</span>";
407: }
408:
409: // Check if the portlet supports requested content type
410: try {
411: configInfo.checkPortletMode(renderRequest.getPortletMode(),
412: renderRequest.getResponseContentType(), request);
413: } catch (PortletModeException ex) {
414: /*
415: PortalServlet.intercept(request, this,
416: Interceptor.ACCESS_GRANTED);
417: */
418: return "Unsupported portlet mode.";
419: } catch (PortletSecurityException ex2) {
420: /*
421: PortalServlet.intercept(request, this,
422: Interceptor.ACCESS_DENIED_NOT_PERMISSIONED);
423: */
424: return "Permission Denied: " + ex2.getMessage();
425: }
426:
427: renderRequest.setAttribute(
428: PortalConstants.PORTLET_CONFIG_ATTRIB,
429: configInfo.config);
430:
431: try {
432: String content = null;
433: if (configInfo.expirationCache == 0) {
434: // Caching is disabled
435: render(renderRequest, renderResponse, request);
436: content = renderResponse.getContent();
437: } else if (configInfo.expirationCache == -1) {
438: HttpSession session = request.getSession();
439: CacheControl cc = PortalUtil.getCacheControl(session,
440: this .id);
441: if (cc == null) {
442: render(renderRequest, renderResponse, request);
443: content = renderResponse.getContent();
444: PortalUtil.cacheContent(session, content, -1,
445: this .id);
446: } else {
447: content = cc.content;
448: }
449:
450: } else {
451: HttpSession session = request.getSession();
452: long currentTime = System.currentTimeMillis() * 1000;
453: CacheControl cc = PortalUtil.getCacheControl(session,
454: this .id);
455: if (cc == null) {
456: render(renderRequest, renderResponse, request);
457: content = renderResponse.getContent();
458: PortalUtil
459: .cacheContent(
460: session,
461: content,
462: currentTime
463: + this .configInfo.cacheExpirationTime,
464: this .id);
465: } else {
466: content = cc.content;
467: if (currentTime > cc.expirationTime) {
468: render(renderRequest, renderResponse, request);
469: content = renderResponse.getContent();
470: cc.content = content;
471: cc.expirationTime = currentTime
472: + this .configInfo.cacheExpirationTime;
473: }
474: }
475: }
476: /*
477: PortalServlet.intercept(request, this,
478: Interceptor.ACCESS_GRANTED);
479: */
480: return content;
481: } catch (UnavailableException ex1) {
482: /*
483: PortalServlet.intercept(request, this,
484: Interceptor.ACCESS_FAILED_PORTLET_NOT_AVAILABLE);
485: */
486: synchronized (configInfo) {
487: if (configInfo.portlet != null
488: && ex1.getUnavailableSeconds() <= 0) {
489: configInfo.portlet = null;
490: configInfo.loadError = ex1.toString();
491: configInfo.loadErrorStackTrace = StringUtil
492: .getErrorStackTraceString(ex1);
493: configInfo.loadStatus = PortletConfigInfo.PORTLET_STATUS_UNAVAILABLE;
494: configInfo.portlet.destroy();
495: }
496: }
497: return "Portlet Unavailable: " + ex1.getMessage();
498: } catch (PortletSecurityException ex2) {
499: /*
500: PortalServlet.intercept(request, this,
501: Interceptor.ACCESS_DENIED_NOT_PERMISSIONED);
502: */
503: return "Permission Denied: " + ex2.getMessage();
504: } catch (PortletException ex3) {
505: PortalServlet.getInstance().error(
506: "Portlet exception in getting portlet content.",
507: ex3);
508: /*
509: PortalServlet.intercept(request, this,
510: Interceptor.ACCESS_FAILED_PORTLET_EXCEPTION);
511: */
512: Throwable originalError = ex3.getCause();
513: Throwable originalError2 = originalError;
514: while (originalError2 != null) {
515: originalError = originalError2;
516: originalError2 = originalError.getCause();
517: }
518: if (originalError != null)
519: return originalError.getMessage();
520: return ex3.getMessage();
521: } catch (Throwable ex4) {
522: PortalServlet.getInstance().error(
523: "Exception in getting portlet content.", ex4);
524: /*
525: PortalServlet.intercept(request, this,
526: Interceptor.ACCESS_FAILED_SYSTEM_EXCEPTION);
527: */
528: return ex4.getMessage();
529:
530: }
531: }
532:
533: public void afterUnmarshal(Unmarshaller um, Object parent) {
534: this .configInfo = PortalServlet.getInstance()
535: .getPortletConfigInfo(this .portletName);
536: }
537:
538: // PortalInterface implementation methods
539: public String getPortletWindowId() {
540: return this .id;
541: }
542:
543: public String getServletRole(String portletRole) {
544: return (String) this .configInfo.securityRoleMapping
545: .get(portletRole);
546:
547: }
548:
549: public void checkPortletMode(PortletMode pMode, String mimeType,
550: HttpServletRequest req) throws PortletModeException,
551: PortletSecurityException {
552: this .configInfo.checkPortletMode(pMode, mimeType, req);
553:
554: }
555:
556: public void checkWindowState(WindowState wState, String mimeType)
557: throws WindowStateException {
558: this .configInfo.checkWindowState(wState, mimeType);
559: }
560:
561: public String createActionURL(boolean isSecure, PortletMode pMode,
562: WindowState wState, Map paramMap,
563: HttpServletRequest request, String baseURL) {
564: return createURL(isSecure, pMode, wState, paramMap, request,
565: baseURL, PortalConstants.PORTAL_ACTION_PROCESS_ACTION);
566: }
567:
568: public String createRenderURL(boolean isSecure, PortletMode pMode,
569: WindowState wState, Map paramMap,
570: HttpServletRequest request, String baseURL) {
571: return createURL(isSecure, pMode, wState, paramMap, request,
572: baseURL, PortalConstants.PORTAL_ACTION_RENDER);
573: }
574:
575: public String createURL(boolean isSecure, PortletMode pMode,
576: WindowState wState, Map paramMap,
577: HttpServletRequest request, String baseURL, String action) {
578: StringBuffer sb = new StringBuffer();
579:
580: if (isSecure) {
581: sb.append(getPortalSecureURLPrefix(request));
582: }
583:
584: sb.append(baseURL);
585: sb.append(action);
586: sb.append("/");
587: sb.append(this .getNumericId());
588:
589: if (pMode != null) {
590: sb.append("/");
591: sb.append(PortalConstants.PORTLET_MODE_TOKEN);
592: sb.append("/");
593: sb.append(pMode.toString());
594: }
595:
596: if (wState != null) {
597: sb.append("/");
598: sb.append(PortalConstants.WINDOW_STATE_TOKEN);
599: sb.append("/");
600: sb.append(wState.toString());
601: }
602:
603: if (paramMap.size() == 0)
604: return sb.toString();
605:
606: sb.append("?");
607: Set entries = paramMap.entrySet();
608: Iterator iter = entries.iterator();
609: Map.Entry element = (Map.Entry) iter.next();
610: String[] values = (String[]) element.getValue();
611:
612: try {
613: for (int i = 0; i < values.length; i++) {
614: sb.append(element.getKey());
615: sb.append("=");
616: sb.append(URLEncoder.encode(values[i], "UTF-8"));
617: }
618: while (iter.hasNext()) {
619: element = (Map.Entry) iter.next();
620: values = (String[]) element.getValue();
621: String name = (String) element.getKey();
622: for (int i = 0; i < values.length; i++) {
623: sb.append("&");
624: sb.append(name);
625: sb.append("=");
626: sb.append(URLEncoder.encode(values[i], "UTF-8"));
627: }
628: }
629: } catch (UnsupportedEncodingException e) {
630: throw new RuntimeException(
631: "UTF-8 encoding is not supported on this server!");
632: }
633: return sb.toString();
634: }
635:
636: protected String getPortalSecureURLPrefix(HttpServletRequest req) {
637: String secureURLPrefix = PortalConfiguration.getInstance()
638: .getPortalSecureURLPrefix();
639: if (secureURLPrefix == null
640: || secureURLPrefix.trim().length() == 0) {
641: int port = req.getServerPort();
642: if (req.isSecure()) {
643: if (port == 443)
644: port = -1;
645: } else {
646: if (port == 80)
647: port = -1;
648: }
649: return "https://" + req.getServerName()
650: + (port == -1 ? "" : ":" + port)
651: + req.getContextPath();
652: }
653: return secureURLPrefix;
654:
655: }
656:
657: public String getConfiguredTitle(Locale l) {
658: return configInfo.config.getResourceBundle(l).getString(
659: "javax.portlet.title");
660: }
661:
662: public boolean removePortletWindow(PortletWindow pWindow) {
663: return false;
664: }
665:
666: private void setupNavState(RenderRequestImpl renderRequest,
667: HttpServletRequest request, boolean isDetached)
668: throws PortletModeException {
669: NavigationState navState = NavigationState.getNavigationState(
670: request.getSession(), getId(), isDetached);
671:
672: if (navState == null) {
673: renderRequest.setPortletMode(PortletMode.VIEW);
674: renderRequest
675: .setParameters(PortletRequestImpl.EMPTY_PARAM_MAP);
676:
677: } else {
678: renderRequest.setPortletMode(navState.portletMode);
679: renderRequest.setParameters(navState.paramMap);
680: }
681:
682: }
683:
684: @SuppressWarnings("unchecked")
685: public String[] getSupportedModes(String mimeType,
686: HttpServletRequest request) throws ServletException {
687: Map allModes = (Map) configInfo.mimeTypeSupport.get(mimeType);
688: if (allModes == null)
689: return new String[0];
690: Iterator iter = allModes.keySet().iterator();
691: Vector acModes = new Vector(5);
692: while (iter.hasNext()) {
693: String mode = (String) iter.next();
694: if (PortletAccessController.getInstance().isAccessible(
695: request, this .configInfo, mode)) {
696: acModes.addElement(mode);
697: }
698: }
699: String[] acModeArray = new String[acModes.size()];
700: acModes.copyInto(acModeArray);
701: return acModeArray;
702: }
703:
704: public void setPortletTemplate(String template) {
705: setTemplate(template);
706: }
707:
708: public void addPortletWindows(List<PortletWindow> windowList) {
709: windowList.add(this );
710:
711: }
712:
713: public PortletPreferences getPreferences(HttpServletRequest req) {
714: SessionCache sCache = (SessionCache) req
715: .getAttribute(PortalConstants.SESSION_CACHE_ATTRIBUTE);
716: return sCache.getPortletPreferences(this );
717: }
718:
719: public PortletConfigInfo getPortletConfigInfo() {
720: return this .configInfo;
721: }
722:
723: public void computeTemplatePath(ServletContext servletContext,
724: String appPath, String theme, String parentTemplate) {
725: if (this.template == null)
726: this.templatePath = PortalUtil.getTemplatePath(
727: servletContext, appPath, theme, parentTemplate);
728: else
729: this.templatePath = PortalUtil.getTemplatePath(
730: servletContext, appPath, theme, this.template);
731: }
732:
733: }
|