/* | |
* Licensed to the Apache Software Foundation (ASF) under one or more | |
* contributor license agreements. See the NOTICE file distributed with | |
* this work for additional information regarding copyright ownership. | |
* The ASF licenses this file to You under the Apache License, Version 2.0 | |
* (the "License"); you may not use this file except in compliance with | |
* the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package org.apache.pluto.driver; | |
import java.io.IOException; | |
import java.io.PrintWriter; | |
import java.io.Writer; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Map; | |
import javax.portlet.PortletException; | |
import javax.portlet.PortletRequest; | |
import javax.servlet.AsyncContext; | |
import javax.servlet.RequestDispatcher; | |
import javax.servlet.ServletContext; | |
import javax.servlet.ServletException; | |
import javax.servlet.http.Cookie; | |
import javax.servlet.http.HttpServlet; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import org.apache.pluto.container.HeaderData; | |
import org.apache.pluto.container.PortletContainer; | |
import org.apache.pluto.container.PortletContainerException; | |
import org.apache.pluto.container.PortletInvokerService; | |
import org.apache.pluto.container.om.portlet.ContainerRuntimeOption; | |
import org.apache.pluto.container.om.portlet.PortletDefinition; | |
import org.apache.pluto.driver.config.DriverConfiguration; | |
import org.apache.pluto.driver.core.PortalRequestContext; | |
import org.apache.pluto.driver.core.PortletWindowImpl; | |
import org.apache.pluto.driver.services.portal.PageConfig; | |
import org.apache.pluto.driver.services.portal.PortletWindowConfig; | |
import org.apache.pluto.driver.url.PortalURL; | |
import org.apache.pluto.driver.url.PortalURL.URLType; | |
import org.apache.pluto.driver.util.PageState; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
/** | |
* The controller servlet used to drive the Portal Driver. All requests mapped to this servlet will be processed as | |
* Portal Requests. | |
* | |
* @version 1.0 | |
* @since Sep 22, 2004 | |
*/ | |
public class PortalDriverServlet extends HttpServlet { | |
private static final long serialVersionUID = 1L; | |
/** Internal Logger. */ | |
private static final Logger LOG = LoggerFactory.getLogger(PortalDriverServlet.class); | |
/** The Portal Driver sServlet Context */ | |
private ServletContext servletContext = null; | |
public static final String DEFAULT_PAGE_URI = "/WEB-INF/themes/pluto-default-theme.jsp"; | |
/** The portlet container to which we will forward all portlet requests. */ | |
protected PortletContainer container = null; | |
/** Character encoding and content type of the response */ | |
private String contentType = ""; | |
// HttpServlet Impl -------------------------------------------------------- | |
public String getServletInfo() { | |
return "Pluto Portal Driver Servlet"; | |
} | |
/** | |
* Initialize the Portal Driver. This method retrieves the portlet container instance from the servlet context scope. | |
* | |
* @see PortletContainer | |
*/ | |
public void init() { | |
servletContext = getServletContext(); | |
container = (PortletContainer) servletContext.getAttribute(AttributeKeys.PORTLET_CONTAINER); | |
String charset = getServletConfig().getInitParameter("charset"); | |
if (charset != null && charset.length() > 0) { | |
contentType = "text/html; charset=" + charset; | |
} | |
} | |
/** | |
* Handle all requests. All POST requests are passed to this method. | |
* | |
* @param request | |
* the incoming HttpServletRequest. | |
* @param response | |
* the incoming HttpServletResponse. | |
* @throws ServletException | |
* if an internal error occurs. | |
* @throws IOException | |
* if an error occurs writing to the response. | |
*/ | |
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
if (LOG.isDebugEnabled()) { | |
LOG.debug("Start of PortalDriverServlet.doGet() to process portlet request . . ."); | |
} | |
if (contentType != "") { | |
response.setContentType(contentType); | |
} | |
PortalRequestContext portalRequestContext = new PortalRequestContext(getServletContext(), request, response); | |
PortalURL portalURL = null; | |
try { | |
portalURL = portalRequestContext.getRequestedPortalURL(); | |
} catch (Exception ex) { | |
String msg = "Cannot handle request for portal URL. Problem: " + ex.getMessage(); | |
LOG.error(msg, ex); | |
throw new ServletException(msg, ex); | |
} | |
String targetWindow = portalURL.getTargetWindow(); | |
// Handle Action, Ajax Action, Partial Action, & Resource requests. | |
// Render requests handled subsequently. | |
if (targetWindow != null && portalURL.getType() != URLType.Render && portalURL.getType() != URLType.Portal) { | |
String reqType = portalURL.getType().toString(); | |
PortletWindowConfig windowConfig = PortletWindowConfig.fromId(targetWindow); | |
PortletWindowImpl portletWindow = new PortletWindowImpl(container, windowConfig, portalURL); | |
if (LOG.isDebugEnabled()) { | |
LOG.debug("Processing " + reqType + " request for window: " + portletWindow.getId().getStringId()); | |
} | |
try { | |
PageState ps; | |
String jsondata; | |
switch (portalURL.getType()) { | |
case Action: | |
container.doAction(portletWindow, request, response, true); | |
break; | |
case AjaxAction: | |
container.doAction(portletWindow, request, response, false); | |
response.setContentType("application/json"); | |
ps = new PageState(request); | |
Writer writer = response.getWriter(); | |
jsondata = ps.toJSONString(); | |
LOG.debug("Ajax Action: returning new page state to client: " + jsondata); | |
writer.write(jsondata); | |
break; | |
case PartialAction: | |
container.doAction(portletWindow, request, response, false); | |
// The page state is made available to the ResourceRequest by | |
// passing | |
// it through all layers, which allows for special case | |
// processing at | |
// some points. | |
ps = new PageState(request); | |
jsondata = ps.toJSONString(); | |
if (LOG.isDebugEnabled()) { | |
LOG.debug("Partial Action: dump page state:\n" + jsondata); | |
} | |
container.doServeResource(portletWindow, request, response, jsondata); | |
break; | |
case Resource: | |
container.doServeResource(portletWindow, request, response, null); | |
break; | |
default: | |
LOG.warn("Unknown request: " + reqType); | |
} | |
} catch (PortletContainerException ex) { | |
LOG.error(ex.getMessage(), ex); | |
throw new ServletException(ex); | |
} catch (PortletException ex) { | |
LOG.error(ex.getMessage(), ex); | |
throw new ServletException(ex); | |
} | |
if (LOG.isDebugEnabled()) { | |
LOG.debug(reqType + " request processed.\n"); | |
} | |
} | |
// Otherwise, handle the render request. | |
else { | |
if (LOG.isDebugEnabled()) { | |
LOG.debug("Processing render request."); | |
} | |
PageConfig pageConfig = portalURL.getPageConfig(servletContext); | |
if (pageConfig == null) { | |
String renderPath = (portalURL == null ? "" : portalURL.getRenderPath()); | |
String msg = "PageConfig for render path [" + renderPath + "] could not be found."; | |
LOG.error(msg); | |
throw new ServletException(msg); | |
} | |
request.setAttribute(AttributeKeys.CURRENT_PAGE, pageConfig); | |
String uri = (pageConfig.getUri() != null) ? pageConfig.getUri() : DEFAULT_PAGE_URI; | |
// Execute header request for each portlet on the page | |
if (LOG.isDebugEnabled()) { | |
LOG.debug("Executing header requests for target portlets."); | |
} | |
String markup = doHeaders(request, response, portalURL); | |
request.setAttribute(AttributeKeys.HEAD_SECTION_MARKUP, markup); | |
if (LOG.isDebugEnabled()) { | |
LOG.debug("Dispatching to: " + uri); | |
} | |
// Dispatch to the JSP that aggregates the page. | |
RequestDispatcher dispatcher = request.getRequestDispatcher(uri); | |
dispatcher.forward(request, response); | |
if (LOG.isDebugEnabled()) { | |
LOG.debug("Render request processed.\n"); | |
} | |
} | |
} | |
/** | |
* Pass all POST requests to {@link #doGet(HttpServletRequest, HttpServletResponse)}. | |
* | |
* @param request | |
* the incoming servlet request. | |
* @param response | |
* the incoming servlet response. | |
* @throws ServletException | |
* if an exception occurs. | |
* @throws IOException | |
* if an exception occurs writing to the response. | |
*/ | |
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
doGet(request, response); | |
} | |
private String doHeaders(HttpServletRequest req, HttpServletResponse resp, PortalURL purl) throws ServletException, | |
IOException { | |
ServletContext sc = req.getServletContext(); | |
DriverConfiguration dc = (DriverConfiguration) sc.getAttribute(AttributeKeys.DRIVER_CONFIG); | |
StringBuilder markup = new StringBuilder(128); | |
for (String pid : purl.getPortletIds()) { | |
PortletWindowConfig wcfg = PortletWindowConfig.fromId(pid); | |
PortletWindowImpl pwin = new PortletWindowImpl(container, wcfg, purl); | |
HeaderData hd = null; | |
try { | |
if (purl.isVersion3(pid)) { | |
hd = container.doHeader(pwin, req, resp); | |
} else if (purl.getVersion(pid).equalsIgnoreCase("2.0")) { | |
String appName = wcfg.getContextPath(); | |
String portletName = PortletWindowConfig.parsePortletName(pid); | |
PortletDefinition pd = dc.getPortletRegistryService().getPortletApplication(appName) | |
.getPortlet(portletName); | |
ContainerRuntimeOption crt = pd.getContainerRuntimeOption("javax.portlet.renderHeaders"); | |
if (crt != null) { | |
List<String> headers = crt.getValues(); | |
if (headers.size() == 1 && headers.get(0).equalsIgnoreCase("true")) { | |
hd = container.doRender(pwin, req, resp, PortletRequest.RENDER_HEADERS); | |
} | |
} | |
} | |
if (hd != null) { | |
// handle markup for document head section | |
markup.append(hd.getHeadSectionMarkup()).append("\n"); | |
// add the cookies to the response | |
List<Cookie> cookies = hd.getCookies(); | |
for (Cookie c : cookies) { | |
resp.addCookie(c); | |
} | |
// Add the HTTP headers to the response | |
Map<String, List<String>> headers = hd.getHttpHeaders(); | |
for (String name : headers.keySet()) { | |
for (String val : headers.get(name)) { | |
resp.addHeader(name, val); | |
} | |
} | |
} | |
} catch (PortletContainerException ex) { | |
LOG.error(ex.getMessage(), ex); | |
throw new ServletException(ex); | |
} catch (PortletException ex) { | |
LOG.error(ex.getMessage(), ex); | |
throw new ServletException(ex); | |
} | |
} | |
return markup.toString(); | |
} | |
} |