001: /*
002: * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
003: * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
004: */
005:
006: package com.sun.portal.harness;
007:
008: import java.util.Map;
009: import java.util.ArrayList;
010: import java.util.List;
011: import java.util.Iterator;
012:
013: import java.net.URL;
014: import java.net.MalformedURLException;
015:
016: import javax.servlet.http.HttpServletRequest;
017: import javax.servlet.http.HttpServletResponse;
018: import javax.servlet.http.HttpSession;
019:
020: import com.sun.portal.providers.ProviderException;
021:
022: import com.sun.portal.providers.portletwindow.PortletWindowProvider;
023: import com.sun.portal.providers.portletwindow.PortletWindowProviderUtils;
024: import com.sun.portal.providers.portletwindow.PortletWindowChannelURL;
025:
026: import com.sun.portal.providers.window.WindowProvider;
027:
028: import com.sun.portal.providers.context.ProviderContext;
029: import com.sun.portal.providers.context.ProviderContextException;
030:
031: import com.sun.portal.providers.containers.ContainerProvider;
032:
033: import com.sun.portal.desktop.context.DesktopAppContext;
034: import com.sun.portal.desktop.context.DesktopAppContextThreadLocalizer;
035:
036: import com.sun.portal.desktop.DesktopRequest;
037:
038: import com.sun.portal.container.WindowState;
039: import com.sun.portal.container.ChannelMode;
040:
041: /**
042: *
043: * This class is the bridge between the Portlet Builder and the
044: * portlet container. It extends PortletWindowProvider to delegate
045: * most of the work to it.
046: *
047: * The <code>getContent</code>() method handles portlet modes of VIEW,
048: * EDIT, and HELP.
049: *
050: * When portlet mode is VIEW, the <code>getContentForPortlets</code>()
051: * method is called, it loops through the portlet names that are
052: * defined in the protlet.xml and calls the
053: * <code>doGetContent</code>()
054: * method to get content for each of the portlet channel, and the
055: * <code>doGetContent</code>() method delegates the work to
056: * PortletWindowProvider's <code>getContent</code>() method.
057: *
058: * When portlet mode is EDIT or HELP, the supper class's <code>getContent</code>()
059: * method is called.
060: *
061: * The <code>processEdit</code>() method sets the target portlet, and
062: * then delegates the process ot PortletWindowProvider's <code>processEdit</code>()
063: * method.
064: *
065: * Since PortletWindowProvider extends from WindowProvider, there are
066: * some abstract methods that are defined in WindowProvider which are
067: * implemented in PortletWindowProvider. This class overrides the
068: * <code>getRoleMap()</code>, <code>getUserInfoMap()</code>,
069: * <code>getEntityID()</code> methods.
070: */
071:
072: public class HarnessPortletProvider extends PortletWindowProvider {
073:
074: //member variables
075: private String _targetPortletChannel;
076: static private List _portletNames;
077: private static final String TARGET_PORTLET_CHANNEL = "targetPortletChannel";
078: private static final String PORTLET_ACTION = "portletAction";
079: private ChannelMode _currentChannelMode = null;
080:
081: //Need to keep this string the same as defined in PortletContainer.java
082: private static String HTTP_SESSION_ID = "javax.portlet.http_session_id";
083:
084: /**
085: * Initialize the target portlet provider class.
086: * <p>
087: * The init method simulates the environment that is expected by
088: * the portlet container.
089: */
090: public void init(String name, HttpServletRequest request)
091: throws ProviderException {
092:
093: HttpSession sess = request.getSession();
094: super .init(name, request);
095: getProviderContext().setSessionProperty(HTTP_SESSION_ID,
096: sess.getId());
097: }
098:
099: /**
100: * This method should be called from the ProviderHarness before the
101: * provider.init() method is called. This is to set the list of
102: * portlets that will be displayed in the target simulator page.
103: *
104: * @param portlets A <code>List</code> of portlet names
105: */
106: static public void setPortlets(List portlets) {
107: _portletNames = portlets;
108: }
109:
110: /**
111: * The getContent() method handles edit, help, and content actions
112: * for the HarnessPortletProvider. For help and edit, it creates a
113: * <code>DesktopRequest</code> and then pass it to the parent
114: * class's <code>getContent()</code> method. For view, it calls
115: * <code>getContentForPortlets()</code) method to get content for
116: * all of the portlets in one page.
117: */
118:
119: public StringBuffer getContent(HttpServletRequest request,
120: HttpServletResponse response) throws ProviderException {
121: String portletMode = (String) request
122: .getParameter(PORTLET_ACTION);
123: String currentPortletMode = (String) request
124: .getParameter(CURRENT_CHANNEL_MODE_KEY);
125: _targetPortletChannel = request
126: .getParameter(TARGET_PORTLET_CHANNEL);
127:
128: //System.out.println("getContent, portletMode: " + portletMode + " currentPortletMode: " + currentPortletMode);
129: //System.out.println("getContent, target portlet: " + _targetPortletChannel);
130:
131: // HACK: in the simulator environment, after process edit, the
132: // same request is passing to getContent, so the current
133: // channel mode is still the old channel mode.
134: if (_targetPortletChannel != null) {
135: if (portletMode == null) {
136: // If there's no
137: // change of mode in the processEdit() process, then
138: // the new channel mode is VIEW, so set it here.
139: setCurrentChannelMode(ChannelMode.VIEW);
140: } else if (portletMode != null
141: && currentPortletMode != null) {
142: setCurrentChannelMode(new ChannelMode(portletMode));
143: }
144: }
145:
146: StringBuffer content = null;
147: DesktopAppContext dac = DesktopAppContextThreadLocalizer.get();
148: DesktopRequest dreq = new DesktopRequest(request, dac, true);
149: if (portletMode != null
150: && (portletMode.equals(ChannelMode.HELP.toString()) || portletMode
151: .equals(ChannelMode.EDIT.toString()))) {
152: if (_targetPortletChannel != null) {
153: content = super .getContent(dreq, response);
154: } else {
155: throw new ProviderException(
156: "HarnessPortletProvider.getContent(): target channel portlet is null");
157: }
158: } else {
159: content = getContentForPortlets(request, response);
160: }
161:
162: portletMode = null;
163: _targetPortletChannel = null;
164: setCurrentChannelMode(null);
165:
166: return content;
167: }
168:
169: /**
170: * This method handles the process action for the
171: * HarnessPortletProvider. It creates a
172: * <code>DesktopRequest</code> and then pass it to the parent
173: * class's <code>processEdit()</code> method.
174: */
175: public URL processEdit(HttpServletRequest request,
176: HttpServletResponse response) throws ProviderException {
177:
178: _targetPortletChannel = (String) request
179: .getParameter(TARGET_PORTLET_CHANNEL);
180: DesktopAppContext dac = DesktopAppContextThreadLocalizer.get();
181: DesktopRequest dreq = new DesktopRequest(request, dac, true);
182: return super .processEdit(dreq, response);
183: }
184:
185: /*
186: * This method loops through the portlets and construct the html blot
187: * for all portlets in one page. It returns a
188: * <code>StringBuffer</code>. The html blot is considered not very likely
189: * to be changed. The reason why the html blot needs to be in the
190: * code is that we want to extend this class from PortletWindowProvider,
191: * to utilize as much functionality as possible. By doing so, then we can
192: * not specify a jsp for the contentPage, since PortletWindowProvider
193: * overrides the getContent() method.
194: *
195: * This method calls doGetContent(), and then doGetContent() calls the
196: * super class's getContent() method.
197: */
198: private StringBuffer getContentForPortlets(
199: HttpServletRequest request, HttpServletResponse response)
200: throws ProviderException {
201:
202: Iterator iter = _portletNames.iterator();
203: int size = _portletNames.size();
204: StringBuffer sb = new StringBuffer();
205: for (int i = 0; i < size; i++) {
206: String providerName = (String) iter.next();
207: boolean hasEditLink = false;
208: URL helpURL = doGetHelp(request, providerName);
209: String title = null;
210: boolean isEditable = false;
211: int idx = 0;
212: try {
213: title = getProviderContext().getStringProperty(
214: providerName, "title", true);
215: idx = title.indexOf(".");
216: if (idx > 0) {
217: title = title.substring(idx + 1);
218: }
219: isEditable = getProviderContext().getBooleanProperty(
220: providerName, "isEditable");
221: } catch (ProviderContextException pce) {
222: throw new ProviderException(
223: "HarnessPortletProvider.getContentForPortlets(): couldn't get title or isEditable property for "
224: + providerName);
225: }
226:
227: sb.append("<TABLE BORDER=\"0\" WIDTH=\"100%\"><TR><TD>")
228: .append(title).append("</TD>");
229: if (isEditable) {
230: hasEditLink = true;
231: sb.append("<TD ALIGN=\"RIGHT\">").append("<A HREF=")
232: .append(
233: getProviderContext().getDesktopURL(
234: request)).append("?").append(
235: ProviderHarness.ARG_ACTION).append("=")
236: .append(ProviderHarness.ACT_CONTENT)
237: .append("&").append(CURRENT_CHANNEL_MODE_KEY)
238: .append("=").append(ChannelMode.EDIT).append(
239: "&").append(TARGET_PORTLET_CHANNEL)
240: .append("=").append(providerName).append("&")
241: .append(PORTLET_ACTION).append("=").append(
242: ChannelMode.EDIT).append(">Edit</A> ");
243: }
244: if (helpURL != null) {
245: if (hasEditLink) {
246: sb.append("<A HREF=").append(helpURL).append(
247: " TARGET=HELP>Help</A>");
248: } else {
249: sb.append("<TD ALIGN=\"RIGHT\">")
250: .append("<A HREF=").append(helpURL).append(
251: " TARGET=HELP>Help</A>");
252: }
253: }
254: sb
255: .append("</TD></TR>")
256: .append(
257: "<TR><TD COLSPAN=\"2\"><hr width=\"100%\" size=\"2\"></TD></TR>")
258: .append("<TR><TD>").append(
259: doGetContent(request, response,
260: providerName).toString());
261: if (i < size) {
262: sb
263: .append("</TD></TR>")
264: .append(
265: "<TR><TD COLSPAN=\"2\"><br><hr width=\"100%\" size=\"2\"></TD></TR>")
266: .append("</TABLE>");
267: }
268: } //for
269: return sb;
270: }
271:
272: /**
273: * Gets the view content for the channel.
274: *
275: * @return StringBuffer holding the content.
276: *
277: * @param req An HttpServletRequest that contains
278: * information related to this request for content.
279: *
280: * @param res An HttpServletResponse that allows the provider
281: * to influence the
282: * overall response for the desktop page (besides generating the content).
283: *
284: * @param targetChannelName the target channel name.
285: *
286: * @exception ProviderException If there was an error generating the
287: * content.
288: *
289: * @see com.sun.portal.providers.PortletWindowProvider#getContent
290: * @see com.sun.portal.providers.ProviderException
291: */
292: public String doGetContent(HttpServletRequest req,
293: HttpServletResponse res, String targetChannelName)
294: throws ProviderException {
295:
296: _targetPortletChannel = targetChannelName;
297: return super .getContent(req, res).toString();
298: }
299:
300: /**
301: * This method is overrided so that the super class's getHelp()
302: * method won't be called. This method returns null so that the
303: * help link for the HarnessPortletChannel in the simulator won't
304: * be shown.
305: * The help links of each individual portlet defined in the portlet.xml,
306: * the doGetHelp() method is used.
307: */
308: public URL getHelp(HttpServletRequest req) throws ProviderException {
309: return null;
310: }
311:
312: /**
313: * Gets the help URL for this provider.
314: * <p>
315: * This method constructs a help URL which will call the
316: * getContent() method on this provider with a parameter
317: * portletAction=HELP.
318: *
319: * @return A URL pointing to the help page for the portlet
320: * channel. A return value of null should signify that this
321: * provider does not have a help page.
322: *
323: */
324: public URL doGetHelp(HttpServletRequest req,
325: String targetPortletChannel) throws ProviderException {
326:
327: String contentType = getProviderContext().getContentType();
328: String hu = null;
329: Map hasHelpMap = null;
330: _targetPortletChannel = targetPortletChannel;
331:
332: try {
333: hasHelpMap = getProviderContext().getCollectionProperty(
334: targetPortletChannel, "hasHelpByMimeType");
335: } catch (ProviderContextException pe) {
336: throw new ProviderException(
337: "HarnessPortletProvider.doGetHelp(): couldn't get collection property for hasHelpByMimeType",
338: pe);
339: }
340:
341: if (hasHelpMap.containsKey(contentType)) {
342: hu = (String) hasHelpMap.get(contentType);
343: }
344:
345: // Check for an empty "helpURL" string, if so do not generate the
346: // help button for the channel.
347: if ((hu != null) && (hu.length() == 0)) {
348: return null;
349: }
350:
351: URL helpURL = null;
352: try {
353: helpURL = getHelpURL(req, getProviderContext());
354: } catch (MalformedURLException mue) {
355: throw new ProviderException(
356: "HarnessPortletProvider.doGetHelp(): couldn't build helpURL",
357: mue);
358: }
359:
360: return helpURL;
361: }
362:
363: private void setCurrentChannelMode(ChannelMode channelMode) {
364: _currentChannelMode = channelMode;
365: }
366:
367: //---------------------------------------------------------------------
368: //
369: // Following methods overrides implementation provided in
370: // PortletWindowProvider.
371: //
372: //---------------------------------------------------------------------
373:
374: /**
375: * EntityID is represented as <web application name>/<portlet name>/<channel name>
376: * <web application name>/<portlet name> is stored in the display profile during
377: * deployment time.
378: *
379: * This method overrides the implementation in
380: * PortletWindowProvider since the target channel is not the
381: * HarnessPortletChannel but the channel defines in the portlet
382: * deployment descriptor.
383: */
384: public String getEntityID(HttpServletRequest req)
385: throws ProviderException {
386: return PortletWindowProviderUtils.getEntityID(req,
387: _targetPortletChannel, getProviderContext());
388: }
389:
390: public Map getRoleMap(HttpServletRequest req)
391: throws ProviderContextException, ProviderException {
392: return PortletWindowProviderUtils.getRoleMap(req,
393: _targetPortletChannel, getProviderContext());
394:
395: }
396:
397: public Map getUserInfoMap(HttpServletRequest req)
398: throws ProviderException {
399: Map map = null;
400: try {
401: map = PortletWindowProviderUtils.getUserInfoMap(req,
402: _targetPortletChannel, getProviderContext());
403: } catch (ProviderContextException pce) {
404: throw new ProviderException(
405: "HarnessPortletProvider.getUserInfoMap():couldn't get userInfoMap property for channel"
406: + _targetPortletChannel, pce);
407:
408: }
409: return map;
410: }
411:
412: //---------------------------------------------------------------------
413: //
414: // Following methods overrides implementation provided in
415: // WindowProvider.
416: //
417: //---------------------------------------------------------------------
418:
419: /**
420: * Gets the title for the channel.
421: * This method returns the title from the portlet.
422: * Portlet uses javax.portlet.title namespace for its title.
423: *
424: * @return A string title.
425: * @exception ProviderException if error occurs when getting the title for
426: * the channel.
427: */
428: public String getTitle() throws ProviderException {
429: if (_targetPortletChannel != null) {
430: return PortletWindowProviderUtils.getTitle(
431: getProviderContext(), _targetPortletChannel);
432: } else {
433: return super .getTitle();
434: }
435: }
436:
437: public String getProcessURL(HttpServletRequest req, String parent,
438: ChannelMode channelMode) {
439:
440: StringBuffer processURL = new StringBuffer(getProviderContext()
441: .getDesktopURL(req));
442: processURL.append("?action=process&").append(
443: TARGET_PORTLET_CHANNEL).append("=").append(
444: _targetPortletChannel).append("&").append(
445: WindowProvider.TARGET_PORTLET_CHANNEL_KEY).append("=")
446: .append(getName()).append("&").append(
447: CURRENT_CHANNEL_MODE_KEY).append("=").append(
448: channelMode.toString());
449:
450: return processURL.toString();
451:
452: }
453:
454: protected URL getEditURL(HttpServletRequest req, String parent,
455: ProviderContext pc) throws MalformedURLException {
456:
457: URL redirectURL = new URL(pc.getDesktopURL(req)
458: + "?action=content&" + PORTLET_ACTION + "="
459: + ChannelMode.EDIT + "&" + TARGET_PORTLET_CHANNEL + "="
460: + _targetPortletChannel);
461: return redirectURL;
462: }
463:
464: /**
465: * EntityID is represented as <web application name>/<portlet name>/<channel name>
466: * <web application name>/<portlet name> is stored in the display profile during
467: * deployment time.
468: */
469: private String getEntityID() throws ProviderException {
470: ProviderContext pc = getProviderContext();
471: String entityIdPrefix = null;
472: try {
473: entityIdPrefix = pc.getStringProperty(
474: _targetPortletChannel, "entityIDPrefix");
475: } catch (ProviderContextException pce) {
476: throw new ProviderException(
477: "HarnessPortletProvider.getEntityID():couldn't get string property for entityIDPrefix",
478: pce);
479: }
480:
481: String entityId = entityIdPrefix + "|" + _targetPortletChannel;
482: return entityId;
483: }
484:
485: protected URL getHelpURL(HttpServletRequest req, ProviderContext pc)
486: throws MalformedURLException {
487:
488: URL helpURL = new URL(pc.getDesktopURL(req)
489: + "?action=content&" + PORTLET_ACTION + "="
490: + ChannelMode.HELP + "&provider=" + getName() + "&"
491: + CURRENT_CHANNEL_MODE_KEY + "=" + ChannelMode.HELP
492: + "&" + TARGET_PORTLET_CHANNEL + "="
493: + _targetPortletChannel + "&last=false");
494: return helpURL;
495: }
496:
497: public String getParentContainerName(HttpServletRequest req)
498: throws ProviderException {
499: return null;
500: }
501:
502: public ContainerProvider getParentContainerProvider(
503: HttpServletRequest req) throws ProviderException {
504:
505: return null;
506: }
507:
508: public boolean isEditable() throws ProviderException {
509: boolean isEditable = false;
510: try {
511: isEditable = getProviderContext().getBooleanProperty(
512: getName(), "isEditable");
513: } catch (ProviderContextException pce) {
514: throw new ProviderException(
515: "HarnessPortletProvider.isEditable: couldn't get isEditable property for "
516: + getName());
517: }
518: return isEditable;
519: }
520:
521: public boolean isPresentable() {
522: return true;
523: }
524:
525: public ChannelMode getCurrentChannelMode(HttpServletRequest req) {
526:
527: //check for local current channel mode
528: if (_currentChannelMode != null) {
529: return _currentChannelMode;
530: } else {
531: return super.getCurrentChannelMode(req);
532: }
533: }
534:
535: }
|