blob: 2572470b2ed8a5875002ae3c7a0353f6338c053c [file] [log] [blame]
/*
* Copyright 2004 The Apache Software Foundation.
*
* Licensed 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.core;
import java.io.IOException;
import java.util.Map;
import javax.portlet.PortletException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pluto.descriptors.portlet.PortletAppDD;
import org.apache.pluto.internal.InternalPortletWindow;
import org.apache.pluto.internal.PortletDescriptorRegistry;
import org.apache.pluto.internal.impl.ActionRequestImpl;
import org.apache.pluto.internal.impl.ActionResponseImpl;
import org.apache.pluto.internal.impl.PortletWindowImpl;
import org.apache.pluto.internal.impl.RenderRequestImpl;
import org.apache.pluto.internal.impl.RenderResponseImpl;
import org.apache.pluto.spi.PortletURLProvider;
import org.apache.pluto.OptionalContainerServices;
import org.apache.pluto.PortletContainer;
import org.apache.pluto.PortletContainerException;
import org.apache.pluto.PortletWindow;
import org.apache.pluto.RequiredContainerServices;
/**
* Default Pluto Container implementation.
*
* @author <a href="mailto:ddewolf@apache.org">David H. DeWolf</a>
* @author <a href="mailto:zheng@apache.org">ZHENG Zhong</a>
* @author <a href="mailto:esm@apache.org">Elliot Metsger</a>
* @version 1.0
* @since Sep 18, 2004
*/
public class PortletContainerImpl implements PortletContainer {
/** Internal logger. */
private static final Log LOG = LogFactory.getLog(PortletContainerImpl.class);
// Private Member Variables ------------------------------------------------
/** The portlet container name. */
private String name = null;
/** The required container services associated with this container. */
private RequiredContainerServices requiredContainerServices = null;
/** The optional container services associated with this container. */
private OptionalContainerServices optionalContainerServices = null;
/** The servlet context associated with this container. */
private ServletContext servletContext = null;
/** 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.
* @param optionalServices the optional container services implementation.
*/
public PortletContainerImpl(String name,
RequiredContainerServices requiredServices,
OptionalContainerServices optionalServices) {
this.name = name;
this.requiredContainerServices = requiredServices;
this.optionalContainerServices = optionalServices;
}
// PortletContainer Impl ---------------------------------------------------
/**
* Initialize the container for use within the given configuration scope.
* @param servletContext the servlet context of the portal webapp.
*/
public void init(ServletContext servletContext)
throws PortletContainerException {
if (servletContext == null) {
throw new PortletContainerException(
"Unable to initialize portlet container [" + name + "]: "
+ "servlet context is null.");
}
this.servletContext = servletContext;
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.servletContext = null;
this.initialized = false;
infoWithName("Container destroyed.");
}
/**
* 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(javax.portlet.RenderRequest,javax.portlet.RenderResponse)
*/
public void doRender(PortletWindow portletWindow,
HttpServletRequest request,
HttpServletResponse response)
throws PortletException, IOException, PortletContainerException {
ensureInitialized();
InternalPortletWindow internalPortletWindow =
new PortletWindowImpl(servletContext, portletWindow);
debugWithName("Render request received for portlet: "
+ portletWindow.getPortletName());
RenderRequestImpl renderRequest = new RenderRequestImpl(
this, internalPortletWindow, request);
RenderResponseImpl renderResponse = new RenderResponseImpl(
this, internalPortletWindow, request, response);
PortletInvoker invoker = new PortletInvoker(internalPortletWindow);
invoker.render(renderRequest, renderResponse);
debugWithName("Portlet rendered for: "
+ portletWindow.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.
* @throws PortletException
* @throws IOException
* @throws PortletContainerException
*
* @see javax.portlet.Portlet#processAction(javax.portlet.ActionRequest,javax.portlet.ActionResponse)
*/
public void doAction(PortletWindow portletWindow,
HttpServletRequest request,
HttpServletResponse response)
throws PortletException, IOException, PortletContainerException {
ensureInitialized();
InternalPortletWindow internalPortletWindow =
new PortletWindowImpl(servletContext, portletWindow);
debugWithName("Action request received for portlet: "
+ portletWindow.getPortletName());
ActionRequestImpl actionRequest = new ActionRequestImpl(
this, internalPortletWindow, request);
ActionResponseImpl actionResponse = new ActionResponseImpl(
this, internalPortletWindow, request, response);
PortletInvoker invoker = new PortletInvoker(internalPortletWindow);
invoker.action(actionRequest, actionResponse);
debugWithName("Portlet action processed for: "
+ portletWindow.getPortletName());
// After processing action, send a redirect URL for rendering.
String location = actionResponse.getRedirectLocation();
if (location == null) {
// Create portlet URL provider to encode redirect URL.
debugWithName("No redirect location specified.");
PortletURLProvider redirectURL = requiredContainerServices
.getPortalCallbackService()
.getPortletURLProvider(request, internalPortletWindow);
// Encode portlet mode if it is changed.
if (actionResponse.getChangedPortletMode() != null) {
redirectURL.setPortletMode(
actionResponse.getChangedPortletMode());
}
// Encode window state if it is changed.
if (actionResponse.getChangedWindowState() != null) {
redirectURL.setWindowState(
actionResponse.getChangedWindowState());
}
// Encode render parameters retrieved from action response.
Map renderParameters = actionResponse.getRenderParameters();
redirectURL.clearParameters();
redirectURL.setParameters(renderParameters);
// Encode redirect URL as a render URL.
redirectURL.setAction(false);
// Set secure of the redirect URL if necessary.
if (actionRequest.isSecure()) {
redirectURL.setSecure();
}
// Encode the redirect URL to a string.
location = actionResponse.encodeRedirectURL(redirectURL.toString());
}
// 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();
InternalPortletWindow internalPortletWindow =
new PortletWindowImpl(servletContext, portletWindow);
debugWithName("Load request received for portlet: "
+ portletWindow.getPortletName());
RenderRequestImpl renderRequest = new RenderRequestImpl(
this, internalPortletWindow, request);
RenderResponseImpl renderResponse = new RenderResponseImpl(
this, internalPortletWindow, request, response);
PortletInvoker invoker = new PortletInvoker(internalPortletWindow);
invoker.load(renderRequest, renderResponse);
debugWithName("Portlet loaded for: " + portletWindow.getPortletName());
}
public String getName() {
return name;
}
public RequiredContainerServices getRequiredContainerServices() {
return requiredContainerServices;
}
/**
* Retrieve the optional container services used by the container.
* If no implementation was provided during construction, the default
* instance will be returned.
*
* @return services used by the container.
*/
public OptionalContainerServices getOptionalContainerServices() {
return optionalContainerServices;
}
public PortletAppDD getPortletApplicationDescriptor(String context)
throws PortletContainerException {
// make sure the container has initialized
ensureInitialized();
// sanity check
if (context == null || context.trim().equals("")) {
final String msg = "Context was null or the empty string.";
errorWithName(msg);
throw new PortletContainerException(msg);
}
// obtain the context of the portlet
ServletContext portletCtx = servletContext.getContext(context);
if (portletCtx == null) {
final String msg = "Unable to obtain the servlet context for " +
"portlet context [" + context + "]. Ensure the portlet has " +
"been deployed and that cross context support is enabled.";
errorWithName(msg);
throw new PortletContainerException(msg);
}
// obtain the portlet application descriptor for the portlet
// context.
PortletAppDD portletAppDD = PortletDescriptorRegistry
.getRegistry()
.getPortletAppDD(portletCtx);
// we can't return null
if (portletAppDD == null) {
final String msg = "Obtained a null portlet application description for " +
"portlet context [" + context + "]";
errorWithName(msg);
throw new PortletContainerException(msg);
}
return portletAppDD;
}
// 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);
}
}
/**
* Prints a message at ERROR level with the container name prefix.
* @param message log message.
*/
private void errorWithName(String message) {
if (LOG.isErrorEnabled()) {
LOG.info("Portlet Container [" + name + "]: " + message);
}
}
}