/* | |
* 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); | |
} | |
} | |