001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/portal/tags/sakai_2-4-1/portal-render-impl/impl/src/java/org/sakaiproject/portal/render/portlet/PortletToolRenderService.java $
003: * $Id: PortletToolRenderService.java 29143 2007-04-19 01:10:38Z ajpoland@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.portal.render.portlet;
021:
022: import java.io.IOException;
023: import java.net.MalformedURLException;
024: import java.util.Enumeration;
025: import java.util.Iterator;
026: import java.util.Properties;
027:
028: import javax.portlet.PortletException;
029: import javax.portlet.PortletMode;
030: import javax.servlet.ServletContext;
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.http.HttpServletResponse;
033: import javax.servlet.http.HttpSession;
034:
035: import org.apache.commons.logging.Log;
036: import org.apache.commons.logging.LogFactory;
037: import org.apache.pluto.PortletContainer;
038: import org.apache.pluto.PortletContainerException;
039: import org.apache.pluto.PortletContainerFactory;
040: import org.apache.pluto.RequiredContainerServices;
041: import org.apache.pluto.core.PortletContextManager;
042: import org.apache.pluto.descriptors.portlet.PortletDD;
043: import org.apache.pluto.descriptors.portlet.SupportsDD;
044: import org.apache.pluto.spi.PortalCallbackService;
045: import org.apache.pluto.spi.PortletURLProvider;
046: import org.sakaiproject.portal.api.PortalService;
047: import org.sakaiproject.portal.render.api.RenderResult;
048: import org.sakaiproject.portal.render.api.ToolRenderException;
049: import org.sakaiproject.portal.render.api.ToolRenderService;
050: import org.sakaiproject.portal.render.portlet.services.SakaiOptionalPortletContainerServices;
051: import org.sakaiproject.portal.render.portlet.services.SakaiPortalCallbackService;
052: import org.sakaiproject.portal.render.portlet.services.SakaiPortalContext;
053: import org.sakaiproject.portal.render.portlet.services.SakaiPortletContainerServices;
054: import org.sakaiproject.portal.render.portlet.services.state.PortletState;
055: import org.sakaiproject.portal.render.portlet.services.state.PortletStateAccess;
056: import org.sakaiproject.portal.render.portlet.services.state.PortletStateEncoder;
057: import org.sakaiproject.portal.render.portlet.servlet.BufferedServletResponse;
058: import org.sakaiproject.portal.render.portlet.servlet.SakaiServletActionRequest;
059: import org.sakaiproject.portal.render.portlet.servlet.SakaiServletRequest;
060: import org.sakaiproject.site.api.ToolConfiguration;
061: import org.sakaiproject.tool.api.Placement;
062:
063: /**
064: * @author ddwolf
065: * @author ieb
066: * @since Sakai 2.4
067: * @version $Rev: 29143 $
068: */
069: public class PortletToolRenderService implements ToolRenderService {
070:
071: /**
072: * Log instance used for all instances of this service.
073: */
074: private static final Log LOG = LogFactory
075: .getLog(PortletToolRenderService.class);
076:
077: /**
078: * Portlet Container instance used by this service.
079: */
080: private PortletContainer container;
081:
082: /**
083: * Portlet Registry used by this service.
084: */
085: private PortletRegistry registry = new PortletRegistry();
086:
087: private PortletStateEncoder portletStateEncoder;
088:
089: private PortalService portalService;
090:
091: public PortletStateEncoder getPortletStateEncoder() {
092: return portletStateEncoder;
093: }
094:
095: public void setPortletStateEncoder(
096: PortletStateEncoder portletStateEncoder) {
097: this .portletStateEncoder = portletStateEncoder;
098: }
099:
100: public boolean preprocess(HttpServletRequest request,
101: HttpServletResponse response, ServletContext context)
102: throws IOException {
103:
104: String stateParam = request
105: .getParameter(SakaiPortalCallbackService.PORTLET_STATE_QUERY_PARAM);
106:
107: // If there is not state parameter, short circuit
108: if (stateParam == null) {
109: return true;
110: }
111:
112: PortletState state = portletStateEncoder.decode(stateParam);
113: PortletStateAccess.setPortletState(request, state);
114:
115: if (LOG.isDebugEnabled()) {
116: LOG.debug("New Portlet State retrieved for Tool '"
117: + state.getId() + ".");
118: }
119:
120: if (state.isAction()) {
121: if (LOG.isDebugEnabled()) {
122: LOG.debug("Processing action for placement id "
123: + state.getId());
124: }
125:
126: PortletStateAccess.setPortletState(request, state);
127: SakaiPortletWindow window = isIn168TestMode(request) ? createPortletWindow(state
128: .getId())
129: : registry.getPortletWindow(state.getId());
130: window.setState(state);
131:
132: try {
133: PortletContainer portletContainer = getPortletContainer(context);
134:
135: portletContainer.doAction(window,
136: new SakaiServletActionRequest(request, state),
137: response);
138:
139: } catch (PortletException e) {
140: throw new ToolRenderException(e.getMessage(), e);
141: } catch (PortletContainerException e) {
142: throw new ToolRenderException(e.getMessage(), e);
143: } finally {
144: state.setAction(false);
145: }
146: return true;
147: }
148: return true;
149: }
150:
151: // Note ToolConfiguration extends Placement
152: public RenderResult render(ToolConfiguration toolConfiguration,
153: final HttpServletRequest request,
154: final HttpServletResponse response, ServletContext context)
155: throws IOException {
156:
157: getPortletDD(toolConfiguration);
158: final SakaiPortletWindow window = isIn168TestMode(request) ? createPortletWindow(toolConfiguration
159: .getId())
160: : registry.getOrCreatePortletWindow(toolConfiguration);
161:
162: PortletState state = PortletStateAccess.getPortletState(
163: request, window.getId().getStringId());
164:
165: if (LOG.isDebugEnabled()) {
166: LOG
167: .debug("Retrieved PortletState from request cache. Applying to window.");
168: }
169:
170: if ("true".equals(request.getParameter(portalService
171: .getResetStateParam()))
172: || "true".equals(portalService.getResetState())) {
173: if (state != null) {
174: String statePrefix = "javax.portlet.p." + state.getId();
175:
176: HttpSession session = request.getSession(true);
177: for (Enumeration e = session.getAttributeNames(); e
178: .hasMoreElements();) {
179: String key = (String) e.nextElement();
180: if (key != null && key.startsWith(statePrefix)) {
181: session.removeAttribute(key);
182: }
183: }
184: state = null; // Remove the remaining evidence of prior
185: // existence
186: }
187: }
188:
189: if (state == null) {
190: state = new PortletState(window.getId().getStringId());
191: PortletStateAccess.setPortletState(request, state);
192: }
193:
194: window.setState(state);
195:
196: try {
197: final HttpServletRequest req = new SakaiServletRequest(
198: request, state);
199: final PortletContainer portletContainer = getPortletContainer(context);
200:
201: // Derive the Edit and Help URLs
202: String editUrl = null;
203: String helpUrl = null;
204: RequiredContainerServices rs = portletContainer
205: .getRequiredContainerServices();
206: PortalCallbackService pcs = rs.getPortalCallbackService();
207: PortletURLProvider pup = null;
208:
209: if (isPortletModeAllowed(toolConfiguration, "edit")) {
210: pup = pcs.getPortletURLProvider(request, window);
211: // System.out.println("pup = "+pup);
212: pup.setPortletMode(new PortletMode("edit"));
213: // System.out.println("pup edit="+pup.toString());
214: editUrl = pup.toString();
215: }
216:
217: if (isPortletModeAllowed(toolConfiguration, "help")) {
218: pup = pcs.getPortletURLProvider(request, window);
219: pup.setPortletMode(new PortletMode("help"));
220: // System.out.println("pup help="+pup.toString());
221: helpUrl = pup.toString();
222: }
223:
224: return new Sakai168RenderResult(req, response,
225: portletContainer, window, helpUrl, editUrl);
226: } catch (PortletContainerException e) {
227: throw new ToolRenderException(e.getMessage(), e);
228: }
229: }
230:
231: private class Sakai168RenderResult implements RenderResult {
232: private HttpServletRequest req = null;
233:
234: private HttpServletResponse response = null;
235:
236: private PortletContainer portletContainer = null;
237:
238: private BufferedServletResponse bufferedResponse = null;
239:
240: private SakaiPortletWindow window = null;
241:
242: private String helpUrl = null;
243:
244: private String editUrl = null;
245:
246: public Sakai168RenderResult(HttpServletRequest req,
247: HttpServletResponse response, PortletContainer pc,
248: SakaiPortletWindow window, String helpUrl,
249: String editUrl) {
250: this .req = req;
251: this .response = response;
252: this .portletContainer = pc;
253: this .window = window;
254: this .helpUrl = helpUrl;
255: this .editUrl = editUrl;
256: }
257:
258: private void renderResponse() throws ToolRenderException {
259: if (bufferedResponse == null) {
260: bufferedResponse = new BufferedServletResponse(response);
261: try {
262: portletContainer.doRender(window, req,
263: bufferedResponse);
264: } catch (PortletException e) {
265: throw new ToolRenderException(e.getMessage(), e);
266: } catch (IOException e) {
267: throw new ToolRenderException(e.getMessage(), e);
268: } catch (PortletContainerException e) {
269: throw new ToolRenderException(e.getMessage(), e);
270: }
271: }
272: }
273:
274: public String getContent() throws ToolRenderException {
275: renderResponse();
276: return bufferedResponse.getInternalBuffer().getBuffer()
277: .toString();
278: }
279:
280: public String getTitle() throws ToolRenderException {
281: renderResponse();
282: return PortletStateAccess.getPortletState(req,
283: window.getId().getStringId()).getTitle();
284: }
285:
286: public String getJSR168EditUrl() {
287: return this .editUrl;
288: }
289:
290: public String getJSR168HelpUrl() {
291: return this .helpUrl;
292: }
293:
294: };
295:
296: // TODO: This must be test code and needs removing
297: private SakaiPortletWindow createPortletWindow(String windowId) {
298: String contextPath = "/rsf";
299: String portletName = "numberguess";
300: return new SakaiPortletWindow(windowId, contextPath,
301: portletName);
302: }
303:
304: private PortletContainer getPortletContainer(ServletContext context)
305: throws PortletContainerException {
306: if (container == null) {
307: container = createPortletContainer();
308: container.init(context);
309: }
310:
311: return container;
312: }
313:
314: private PortletContainer createPortletContainer()
315: throws PortletContainerException {
316: SakaiPortletContainerServices services = new SakaiPortletContainerServices();
317: SakaiOptionalPortletContainerServices optServices = new SakaiOptionalPortletContainerServices();
318: services
319: .setPortalCallbackService(new SakaiPortalCallbackService());
320: services.setPortalContext(new SakaiPortalContext());
321: return PortletContainerFactory.getInstance().createContainer(
322: "sakai", services, optServices);
323: }
324:
325: private static boolean isIn168TestMode(HttpServletRequest request) {
326: HttpSession session = request.getSession(true);
327: if (session.getAttribute("test168") != null
328: || request.getParameter("test168") != null) {
329: request.getSession(true).setAttribute("test168",
330: Boolean.TRUE.toString());
331: return true;
332: }
333: return false;
334: }
335:
336: private boolean isPortletApplication(ServletContext context,
337: ToolConfiguration configuration)
338: throws ToolRenderException, MalformedURLException {
339: SakaiPortletWindow window = registry
340: .getOrCreatePortletWindow(configuration);
341: if (window == null) {
342: return false;
343: }
344: if (LOG.isDebugEnabled()) {
345: LOG.debug("Checking context for potential portlet ");
346: }
347: ServletContext crossContext = context.getContext(window
348: .getContextPath());
349: if (LOG.isDebugEnabled()) {
350: LOG.debug("Got servlet context as " + crossContext);
351: LOG.debug("Getting Context for path "
352: + window.getContextPath());
353: LOG.debug("Base Path " + crossContext.getRealPath("/"));
354: LOG.debug("Context Name "
355: + crossContext.getServletContextName());
356: LOG.debug("Server Info " + crossContext.getServerInfo());
357: LOG
358: .debug(" and it is a portlet ? :"
359: + (crossContext
360: .getResource("/WEB-INF/portlet.xml") != null));
361: }
362: return crossContext.getResource("/WEB-INF/portlet.xml") != null;
363: }
364:
365: public boolean accept(ToolConfiguration configuration,
366: HttpServletRequest request, HttpServletResponse response,
367: ServletContext context) {
368: try {
369: if (isIn168TestMode(request)) {
370: LOG.warn("In portlet test mode");
371: return true;
372: }
373: if (isPortletApplication(context, configuration)) {
374: if (LOG.isDebugEnabled()) {
375: LOG.debug("Tool " + configuration.getToolId()
376: + " is a portlet");
377: }
378: return true;
379: }
380: if (LOG.isDebugEnabled()) {
381: LOG.debug("Tool " + configuration.getToolId()
382: + " is not a portlet");
383: }
384: return false;
385: } catch (MalformedURLException e) {
386: LOG.error("Failed to render ", e);
387: return false;
388: } catch (ToolRenderException e) {
389: LOG.error("Failed to render ", e);
390: return false;
391: }
392: }
393:
394: public void reset(ToolConfiguration configuration) {
395: registry.reset(configuration);
396: }
397:
398: public PortletDD getPortletDD(Placement placement) {
399: Properties toolProperties = placement.getPlacementConfig();
400: String portletName = null;
401: String appName = null;
402: String fred = null;
403:
404: if (toolProperties != null) {
405: // System.out.println("tp = "+toolProperties);
406: portletName = toolProperties
407: .getProperty(PortalService.TOOL_PORTLET_NAME);
408: appName = toolProperties
409: .getProperty(PortalService.TOOL_PORTLET_APP_NAME);
410: fred = toolProperties.getProperty("FRED");
411: }
412: // System.out.println("appName="+appName);
413: // System.out.println("portletName="+portletName);
414: // System.out.println("fred="+fred);
415: Properties configProperties = placement.getConfig();
416: if (configProperties != null) {
417: if (portletName == null) {
418: portletName = configProperties
419: .getProperty(PortalService.TOOL_PORTLET_NAME);
420: }
421: if (appName == null) {
422: appName = configProperties
423: .getProperty(PortalService.TOOL_PORTLET_APP_NAME);
424: }
425: }
426: // System.out.println("appName="+appName);
427: // System.out.println("portletName="+portletName);
428: PortletDD pdd = PortletContextManager.getManager()
429: .getPortletDescriptor(appName, portletName);
430: // System.out.println("pdd="+pdd);
431: return pdd;
432: }
433:
434: public boolean isPortletModeAllowed(Placement placement, String mode) {
435: if (placement == null || mode == null)
436: return false;
437: PortletDD pdd = getPortletDD(placement);
438: if (pdd == null)
439: return true;
440: Iterator supports = pdd.getSupports().iterator();
441: while (supports.hasNext()) {
442: SupportsDD sup = (SupportsDD) supports.next();
443: Iterator modes = sup.getPortletModes().iterator();
444: while (modes.hasNext()) {
445: if (modes.next().toString().equalsIgnoreCase(
446: mode.toString())) {
447: return true;
448: }
449: }
450: }
451: return false;
452: }
453:
454: /**
455: * @return the portalService
456: */
457: public PortalService getPortalService() {
458: return portalService;
459: }
460:
461: /**
462: * @param portalService
463: * the portalService to set
464: */
465: public void setPortalService(PortalService portalService) {
466: this.portalService = portalService;
467: }
468: }
|