/*
* 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.jetspeed.container.invoker;
import java.io.IOException;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.jetspeed.PortalReservedParameters;
import org.apache.jetspeed.container.FilterManager;
import org.apache.jetspeed.container.PortletWindow;
import org.apache.jetspeed.factory.PortletFactory;
import org.apache.jetspeed.factory.PortletInstance;
import org.apache.jetspeed.om.portlet.PortletApplication;
import org.apache.jetspeed.om.portlet.PortletDefinition;
import org.apache.jetspeed.om.window.impl.PortletWindowImpl;
import org.apache.jetspeed.request.JetspeedRequestContext;
import org.apache.pluto.container.PortletInvokerService;
import org.apache.pluto.container.PortletRequestContext;
import org.apache.pluto.container.PortletResponseContext;
/**
* ServletPortletInvoker invokes portlets in another web application, calling a
* portlet's render or action method via a cross context request dispatcher.
* In order for this class to work, a servlet must be special servlet must be
* infused into the web (portlet) application. This servlet knows how to delegate
* to portlets and package their response back into a servlet response.
* The context name of the servlet should be configurable. The default context name is "/container"
* ServletPortletInvokerFactory is the factory for creating portlet invokers that
* use Jetspeed Container servlet.
* <h3>Sample Factory Configuration</h3>
* <pre>
* <code>
* factory.invoker.servlet = org.apache.jetspeed.container.invoker.ServletPortletInvoker
* factory.invoker.servlet.pool.size = 50
* factory.invoker.servlet.mapping.name = /container
* </code>
* </pre>
* @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
* @version $Id: ServletPortletInvoker.java 767444 2009-04-22 10:08:53Z ate $
*/
public class ServletPortletInvoker implements JetspeedPortletInvoker
{
private final static Logger log = LoggerFactory.getLogger(ServletPortletInvoker.class);
protected PortletFactory portletFactory;
protected ServletContext jetspeedContext;
protected ServletConfig jetspeedConfig;
protected PortletDefinition portletDefinition;
protected boolean activated = false;
protected String servletMappingName;
/**
* requestResponseUnwrapper used to unwrap container request or portlet response
* to find the real servlet request or servlet response.
*/
protected ContainerRequestResponseUnwrapper requestResponseUnwrapper;
public ServletPortletInvoker(ContainerRequestResponseUnwrapper requestResponseUnwrapper, String servletMappingName)
{
this.requestResponseUnwrapper = requestResponseUnwrapper;
this.servletMappingName = servletMappingName;
}
public void activate(PortletFactory portletFactory, PortletDefinition portletDefinition, ServletConfig servletConfig)
{
this.portletFactory = portletFactory;
this.jetspeedConfig = servletConfig;
jetspeedContext = servletConfig.getServletContext();
this.portletDefinition = portletDefinition;
activated = true;
}
public void passivate()
{
activated = false;
}
public boolean isActivated()
{
return activated;
}
/**
* Creates a servlet request dispatcher to dispatch to another web application to render the portlet.
* NOTE: this method requires that your container supports cross-context dispatching.
* Cross-context dispatching is known to work on Tomcat, Catalina, Tomcat-5.
*
* @param portletRequest
* @param portletResponse
* @param methodID
* @throws PortletException
* @throws IOException
*/
public void invoke(PortletRequestContext requestContext, PortletRequest portletRequest, PortletResponse portletResponse,
PortletWindow.Action action, FilterManager filter)
throws PortletException, IOException
{
PortletWindowImpl window = (PortletWindowImpl)requestContext.getPortletWindow();
PortletDefinition portletDefinition = window.getPortletDefinition();
PortletApplication app = portletDefinition.getApplication();
String appContextPath = app.getContextPath();
ServletContext appContext = jetspeedContext.getContext(appContextPath);
if (null == appContext)
{
String message = "Failed to find Servlet context for Portlet Application: " + appContextPath;
log.error(message);
throw new PortletException(message);
}
PortletInstance portletInstance = portletFactory.getPortletInstance(appContext, portletDefinition);
RequestDispatcher dispatcher = appContext.getRequestDispatcher(servletMappingName);
if (null == dispatcher)
{
String message = "Failed to get Request Dispatcher for Portlet Application: "+appContextPath+", servlet: "+servletMappingName;
log.error(message);
throw new PortletException(message);
}
boolean useForward = window.getAttribute(PortalReservedParameters.PORTLET_CONTAINER_INVOKER_USE_FORWARD) != null;
try
{
PortletResponseContext responseContext = (PortletResponseContext)portletRequest.getAttribute(PortletInvokerService.RESPONSE_CONTEXT);
((JetspeedRequestContext)window.getRequestContext()).setCurrentPortletWindow(window);
window.setInvocationState(action, requestContext, responseContext, portletRequest, portletResponse, portletInstance);
window.setAttribute(PortalReservedParameters.FRAGMENT_ATTRIBUTE, window.getFragment());
window.setAttribute(PortalReservedParameters.PORTLET_WINDOW_ATTRIBUTE, window);
window.setAttribute(PortalReservedParameters.PORTLET_DEFINITION_ATTRIBUTE, portletDefinition);
window.setAttribute(PortalReservedParameters.PORTLET_FILTER_MANAGER_ATTRIBUTE, filter);
ServletRequest request = this.requestResponseUnwrapper.unwrapContainerRequest(requestContext.getContainerRequest());
ServletResponse response = this.requestResponseUnwrapper.unwrapContainerResponse(requestContext.getContainerResponse());
if (useForward)
{
dispatcher.forward(request, response);
}
else
{
dispatcher.include(request, response);
}
}
catch (Exception e)
{
String message =
"Failed to dispatch."+(useForward?"forward":"include")+" for Portlet Application: "+appContextPath+", servlet: "+servletMappingName;
log.error(message, e);
throw new PortletException(message, e);
}
finally
{
((JetspeedRequestContext)window.getRequestContext()).setCurrentPortletWindow(null);
}
}
}