blob: a4d87a4bfac925401a7930c98fef60c66d4d38e6 [file] [log] [blame]
/*
* 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.container.impl;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.Event;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.HeaderRequest;
import javax.portlet.HeaderResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.namespace.QName;
import org.apache.pluto.container.ContainerServices;
import org.apache.pluto.container.FilterManager;
import org.apache.pluto.container.HeaderData;
import org.apache.pluto.container.PortletActionResponseContext;
import org.apache.pluto.container.PortletContainer;
import org.apache.pluto.container.PortletContainerException;
import org.apache.pluto.container.PortletEnvironmentService;
import org.apache.pluto.container.PortletEventResponseContext;
import org.apache.pluto.container.PortletHeaderResponseContext;
import org.apache.pluto.container.PortletInvokerService;
import org.apache.pluto.container.PortletRenderResponseContext;
import org.apache.pluto.container.PortletRequestContext;
import org.apache.pluto.container.PortletRequestContextService;
import org.apache.pluto.container.PortletResourceRequestContext;
import org.apache.pluto.container.PortletResourceResponseContext;
import org.apache.pluto.container.PortletWindow;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Default Pluto Container implementation.
*
* @version 1.0
* @since Sep 18, 2004
*/
public class PortletContainerImpl implements PortletContainer
{
/** Internal logger. */
private static final Logger LOG = LoggerFactory.getLogger(PortletContainerImpl.class);
// Private Member Variables ------------------------------------------------
/** The portlet container name. */
private final String name;
/** The container services associated with this container. */
private final ContainerServices containerServices;
/** Flag indicating whether or not we've been initialized. */
private boolean initialized = false;
// Constructor -------------------------------------------------------------
/** Default Constructor. Create a container implementation
* whith the given name and given services.
*
* @param name the name of the container.
* @param requiredServices the required container services implementation.
*/
public PortletContainerImpl(String name,
ContainerServices requiredServices) {
this.name = name;
this.containerServices = requiredServices;
}
// PortletContainer Impl ---------------------------------------------------
/**
* Initialize the container for use within the given configuration scope.
*/
public void init()
throws PortletContainerException {
this.initialized = true;
infoWithName("Container initialized successfully.");
}
/**
* Determine whether this container has been initialized or not.
* @return true if the container has been initialized.
*/
public boolean isInitialized() {
return initialized;
}
/**
* Destroy this container.
*/
public void destroy() {
this.initialized = false;
infoWithName("Container destroyed.");
}
/**
* Performs Header request for the portlet associated with the specified portlet window.
* @param portletWindow the portlet window.
* @param request the servlet request.
* @param response the servlet response.
* @throws IllegalStateException if the container is not initialized.
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*
* @see javax.portlet.Portlet#header(HeaderRequest, HeaderResponse)
*/
@Override
public HeaderData doHeader(PortletWindow portletWindow,
HttpServletRequest request,
HttpServletResponse response)
throws PortletException, IOException, PortletContainerException
{
ensureInitialized();
debugWithName("Header request received for portlet: "
+ portletWindow.getPortletDefinition().getPortletName());
PortletRequestContextService rcService = getContainerServices().getPortletRequestContextService();
PortletEnvironmentService envService = getContainerServices().getPortletEnvironmentService();
PortletInvokerService invoker = getContainerServices().getPortletInvokerService();
PortletRequestContext requestContext = rcService.getPortletHeaderRequestContext(this, request, response, portletWindow);
PortletHeaderResponseContext responseContext = rcService.getPortletHeaderResponseContext(this, request, response, portletWindow, requestContext);
responseContext.setPropsAllowed(true);
HeaderRequest portletRequest = envService.createHeaderRequest(requestContext, responseContext);
HeaderResponse portletResponse = envService.createHeaderResponse(responseContext);
HeaderData headerData = new HeaderData();
FilterManager filterManager = filterInitialisation(portletWindow,PortletRequest.HEADER_PHASE);
try
{
invoker.header(requestContext, portletRequest, portletResponse, filterManager);
headerData = responseContext.getHeaderData();
responseContext.close();
}
finally
{
responseContext.release();
}
debugWithName("Portlet header done for: " + portletWindow.getPortletDefinition().getPortletName());
return headerData;
}
/**
* Renders the portlet associated with the specified portlet window.
* @param portletWindow the portlet window.
* @param request the servlet request.
* @param response the servlet response.
* @throws IllegalStateException if the container is not initialized.
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*
* @see javax.portlet.Portlet#render(RenderRequest, RenderResponse)
*/
@Override
public HeaderData doRender(PortletWindow portletWindow,
HttpServletRequest request,
HttpServletResponse response,
String renderHeaders)
throws PortletException, IOException, PortletContainerException
{
ensureInitialized();
debugWithName("Render request received for portlet: "
+ portletWindow.getPortletDefinition().getPortletName());
PortletRequestContextService rcService = getContainerServices().getPortletRequestContextService();
PortletEnvironmentService envService = getContainerServices().getPortletEnvironmentService();
PortletInvokerService invoker = getContainerServices().getPortletInvokerService();
PortletRequestContext requestContext = rcService.getPortletRenderRequestContext(this, request, response, portletWindow);
PortletRenderResponseContext responseContext = rcService.getPortletRenderResponseContext(this, request, response, portletWindow, requestContext);
if (renderHeaders != null && renderHeaders.equals(PortletRequest.RENDER_HEADERS)) {
responseContext.setPropsAllowed(true);
} else {
responseContext.setPropsAllowed(false);
}
requestContext.setRenderHeaders(renderHeaders);
HeaderData headerData = new HeaderData();
RenderRequest portletRequest = envService.createRenderRequest(requestContext, responseContext);
RenderResponse portletResponse = envService.createRenderResponse(responseContext);
FilterManager filterManager = filterInitialisation(portletWindow,PortletRequest.RENDER_PHASE);
try
{
invoker.render(requestContext, portletRequest, portletResponse, filterManager);
headerData = responseContext.getHeaderData();
responseContext.close();
}
finally
{
responseContext.release();
}
debugWithName("Portlet render done for: " + portletWindow.getPortletDefinition().getPortletName());
return headerData;
}
/**
* Indicates that a portlet resource Serving occured in the current request and calls
* the processServeResource method of this portlet.
* @param portletWindow the portlet Window
* @param request the servlet request
* @param response the servlet response
* @throws PortletException if one portlet has trouble fulfilling
* the request
* @throws PortletContainerException if the portlet container implementation
* has trouble fulfilling the request
*/
public void doServeResource(PortletWindow portletWindow,
HttpServletRequest request,
HttpServletResponse response)
throws PortletException, IOException, PortletContainerException
{
ensureInitialized();
debugWithName("Resource request received for portlet: "
+ portletWindow.getPortletDefinition().getPortletName());
PortletRequestContextService rcService = getContainerServices().getPortletRequestContextService();
PortletEnvironmentService envService = getContainerServices().getPortletEnvironmentService();
PortletInvokerService invoker = getContainerServices().getPortletInvokerService();
PortletResourceRequestContext requestContext = rcService.getPortletResourceRequestContext(this, request, response, portletWindow);
PortletResourceResponseContext responseContext = rcService.getPortletResourceResponseContext(this, request, response, portletWindow, requestContext);
responseContext.setPropsAllowed(true);
ResourceRequest portletRequest = envService.createResourceRequest(requestContext, responseContext);
ResourceResponse portletResponse = envService.createResourceResponse(responseContext, requestContext.getCacheability());
requestContext.setResponse(portletResponse); // for async support
FilterManager filterManager = filterInitialisation(portletWindow,PortletRequest.RESOURCE_PHASE);
try
{
invoker.serveResource(requestContext, portletRequest, portletResponse, filterManager);
}
finally
{
if (!request.isAsyncSupported() || !request.isAsyncStarted()) {
// Mark portlet interaction is completed: backend implementation can flush response state now
responseContext.close();
responseContext.release();
} else {
LOG.debug("Async started for resource request. responseContext not released.");
}
}
debugWithName("Portlet resource done for: " + portletWindow.getPortletDefinition().getPortletName());
}
/**
* Process action for the portlet associated with the given portlet window.
* @param portletWindow the portlet window.
* @param request the servlet request.
* @param response the servlet response.
* @param isRedirect Flag indicating whether redirect is to be performed.
* should be true for Action request and false for Ajax Action or
* Partial Action requests.
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*
* @see javax.portlet.Portlet#processAction(ActionRequest, ActionResponse)
*/
public void doAction(PortletWindow portletWindow,
HttpServletRequest request,
HttpServletResponse response,
boolean isRedirect)
throws PortletException, IOException, PortletContainerException
{
ensureInitialized();
debugWithName("Action request received for portlet: "
+ portletWindow.getPortletDefinition().getPortletName());
PortletRequestContextService rcService = getContainerServices().getPortletRequestContextService();
PortletEnvironmentService envService = getContainerServices().getPortletEnvironmentService();
PortletInvokerService invoker = getContainerServices().getPortletInvokerService();
PortletRequestContext requestContext = rcService.getPortletActionRequestContext(this, request, response, portletWindow);
PortletActionResponseContext responseContext = rcService.getPortletActionResponseContext(this, request, response, portletWindow, requestContext);
responseContext.setPropsAllowed(true);
ActionRequest portletRequest = envService.createActionRequest(requestContext, responseContext);
ActionResponse portletResponse = envService.createActionResponse(responseContext);
FilterManager filterManager = filterInitialisation(portletWindow,PortletRequest.ACTION_PHASE);
String location = null;
String logtxt = "Portlet action";
if (!isRedirect) {
logtxt = "Portlet Ajax or Partial action";
}
try
{
invoker.action(requestContext, portletRequest, portletResponse, filterManager);
debugWithName(logtxt + " processed for: "
+ portletWindow.getPortletDefinition().getPortletName());
// add http headers to response
responseContext.processHttpHeaders();
// Mark portlet interaction is completed: backend implementation can flush response state now
responseContext.close();
if (!responseContext.isRedirect())
{
List<Event> events = responseContext.getEvents();
if (!events.isEmpty())
{
getContainerServices().getEventCoordinationService().processEvents(this, portletWindow, request, response, events);
}
}
} catch (Throwable t) {
// Throw away events and parameters that were set
responseContext.reset();
// just swallow the exception, ignoring changes to the response
StringBuilder txt = new StringBuilder(128);
txt.append("Exception during action request processing. Exception: ");
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
pw.flush();
txt.append(sw.toString());
LOG.warn(txt.toString());
}
finally
{
// After processing action and possible event handling, retrieve the target response URL to be redirected to
// This can either be a renderURL or an external URL (optionally containing a future renderURL as query parameter
location = response.encodeRedirectURL(responseContext.getResponseURL());
responseContext.release();
}
if (isRedirect) {
redirect(request, response, location);
}
debugWithName(logtxt + " done for: " + portletWindow.getPortletDefinition().getPortletName());
}
protected void redirect(HttpServletRequest request, HttpServletResponse response, String location) throws IOException
{
// Here we intentionally use the original response
// instead of the wrapped internal response.
response.sendRedirect(location);
debugWithName("Redirect URL sent.");
}
/**
* Loads the portlet associated with the specified portlet window.
* @param portletWindow the portlet window.
* @param request the servlet request.
* @param response the servlet response.
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*/
public void doLoad(PortletWindow portletWindow,
HttpServletRequest request,
HttpServletResponse response)
throws PortletException, IOException, PortletContainerException
{
ensureInitialized();
debugWithName("Load request received for portlet: "
+ portletWindow.getPortletDefinition().getPortletName());
PortletRequestContextService rcService = getContainerServices().getPortletRequestContextService();
PortletEnvironmentService envService = getContainerServices().getPortletEnvironmentService();
PortletInvokerService invoker = getContainerServices().getPortletInvokerService();
PortletRequestContext requestContext = rcService.getPortletRenderRequestContext(this, request, response, portletWindow);
PortletRenderResponseContext responseContext = rcService.getPortletRenderResponseContext(this, request, response, portletWindow, requestContext);
RenderRequest portletRequest = envService.createRenderRequest(requestContext, responseContext);
RenderResponse portletResponse = envService.createRenderResponse(responseContext);
try
{
invoker.load(requestContext, portletRequest, portletResponse);
// Mark portlet interaction is completed: backend implementation can flush response state now
responseContext.close();
}
finally
{
responseContext.release();
}
debugWithName("Portlet load done for: " + portletWindow.getPortletDefinition().getPortletName());
}
public void doAdmin(PortletWindow portletWindow,
HttpServletRequest request,
HttpServletResponse response)
throws PortletException, IOException, PortletContainerException
{
ensureInitialized();
debugWithName("Admin request received for portlet: "
+portletWindow.getPortletDefinition().getPortletName());
PortletRequestContextService rcService = getContainerServices().getPortletRequestContextService();
PortletEnvironmentService envService = getContainerServices().getPortletEnvironmentService();
PortletInvokerService invoker = getContainerServices().getPortletInvokerService();
PortletRequestContext requestContext = rcService.getPortletRenderRequestContext(this, request, response, portletWindow);
PortletRenderResponseContext responseContext = rcService.getPortletRenderResponseContext(this, request, response, portletWindow, requestContext);
RenderRequest portletRequest = envService.createRenderRequest(requestContext, responseContext);
RenderResponse portletResponse = envService.createRenderResponse(responseContext);
try
{
invoker.admin(requestContext, portletRequest, portletResponse);
// Mark portlet interaction is completed: backend implementation can flush response state now
responseContext.close();
}
finally
{
responseContext.release();
}
debugWithName("Portlet admin request done for: " + portletWindow.getPortletDefinition().getPortletName());
}
/**
* @see org.apache.pluto.container.PortletContainer#getName()
*/
public String getName() {
return name;
}
/**
* @see org.apache.pluto.container.PortletContainer#getContainerServices()
*/
public ContainerServices getContainerServices() {
return containerServices;
}
/**
* Fire Event for the portlet associated with the given portlet window and eventName
* @param portletWindow the portlet window.
* @param request the servlet request.
* @param response the servlet response.
* @param event the event
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*
* @see javax.portlet.EventPortlet#processEvent(javax.portlet.EventRequest, javax.portlet.EventResponse)
*/
public void doEvent(PortletWindow portletWindow,
HttpServletRequest request,
HttpServletResponse response,
Event event)
throws PortletException, IOException, PortletContainerException
{
ensureInitialized();
debugWithName("Event: "+event.getName()+" received for portlet: "
+ portletWindow.getPortletDefinition().getPortletName());
PortletRequestContextService rcService = getContainerServices().getPortletRequestContextService();
PortletEnvironmentService envService = getContainerServices().getPortletEnvironmentService();
PortletInvokerService invoker = getContainerServices().getPortletInvokerService();
PortletRequestContext requestContext = rcService.getPortletEventRequestContext(this, request, response, portletWindow);
PortletEventResponseContext responseContext = rcService.getPortletEventResponseContext(this, request, response, portletWindow, requestContext);
responseContext.setPropsAllowed(true);
EventRequest portletRequest = envService.createEventRequest(requestContext, responseContext, event);
EventResponse portletResponse = envService.createEventResponse(responseContext);
FilterManager filterManager = filterInitialisation(portletWindow,PortletRequest.EVENT_PHASE);
List<Event> events = null;
try
{
invoker.event(requestContext, portletRequest, portletResponse, filterManager);
debugWithName("Portlet event processed for: "
+ portletWindow.getPortletDefinition().getPortletName());
// add http headers to response
responseContext.processHttpHeaders();
// Mark portlet interaction is completed: backend implementation can flush response state now
responseContext.close();
events = responseContext.getEvents();
} catch (Throwable t) {
// Throw away events and parameters that were set
responseContext.reset();
// just swallow the exception, ignoring changes to the response
StringBuilder txt = new StringBuilder(128);
txt.append("Exception during action request processing. Exception: ");
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
pw.flush();
txt.append(sw.toString());
LOG.warn(txt.toString());
}
finally
{
responseContext.release();
}
if (events != null && !events.isEmpty())
{
getContainerServices().getEventCoordinationService().processEvents(this, portletWindow, request, response, events);
}
debugWithName("Portlet event: "+ event.getName() +" fired for: " + portletWindow.getPortletDefinition().getPortletName());
}
// Private Methods ---------------------------------------------------------
/**
* Ensures that the portlet container is initialized.
* @throws IllegalStateException if the container is not initialized.
*/
private void ensureInitialized() throws IllegalStateException {
if (!isInitialized()) {
throw new IllegalStateException(
"Portlet container [" + name + "] is not initialized.");
}
}
/**
* Prints a message at DEBUG level with the container name prefix.
* @param message log message.
*/
private void debugWithName(String message) {
if (LOG.isDebugEnabled()) {
LOG.debug("Portlet Container [" + name + "]: " + message);
}
}
/**
* Prints a message at INFO level with the container name prefix.
* @param message log message.
*/
private void infoWithName(String message) {
if (LOG.isInfoEnabled()) {
LOG.info("Portlet Container [" + name + "]: " + message);
}
}
/**
* The method initialise the FilterManager for later use in the PortletServlet
* @param portletWindow the PortletWindow
* @param lifeCycle like ACTION_PHASE, RENDER_PHASE,...
* @return FilterManager
* @throws PortletContainerException
*/
private FilterManager filterInitialisation(PortletWindow portletWindow, String lifeCycle) throws PortletContainerException{
return getContainerServices().getFilterManagerService().getFilterManager(portletWindow, lifeCycle);
}
}