1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.container.invoker;
18
19 import java.io.IOException;
20
21 import javax.portlet.ActionRequest;
22 import javax.portlet.ActionResponse;
23 import javax.portlet.PortletException;
24 import javax.portlet.PortletRequest;
25 import javax.portlet.PortletResponse;
26 import javax.portlet.RenderRequest;
27 import javax.portlet.RenderResponse;
28 import javax.servlet.RequestDispatcher;
29 import javax.servlet.ServletConfig;
30 import javax.servlet.ServletContext;
31 import javax.servlet.ServletRequest;
32 import javax.servlet.ServletResponse;
33 import javax.servlet.http.HttpServletRequestWrapper;
34 import javax.servlet.http.HttpServletResponseWrapper;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.apache.jetspeed.PortalReservedParameters;
39 import org.apache.jetspeed.container.ContainerConstants;
40 import org.apache.jetspeed.container.PortletRequestContext;
41 import org.apache.jetspeed.factory.PortletFactory;
42 import org.apache.jetspeed.factory.PortletInstance;
43 import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
44 import org.apache.jetspeed.request.RequestContext;
45 import org.apache.jetspeed.aggregator.Worker;
46 import org.apache.jetspeed.aggregator.CurrentWorkerContext;
47 import org.apache.pluto.om.portlet.PortletDefinition;
48 import org.apache.pluto.om.servlet.WebApplicationDefinition;
49
50 /***
51 * ServletPortletInvoker invokes portlets in another web application, calling a
52 * portlet's render or action method via a cross context request dispatcher.
53 * In order for this class to work, a servlet must be special servlet must be
54 * infused into the web (portlet) application. This servlet knows how to delegate
55 * to portlets and package their response back into a servlet response.
56 * The context name of the servlet should be configurable. The default context name is "/container"
57 * ServletPortletInvokerFactory is the factory for creating portlet invokers that
58 * use Jetspeed Container servlet.
59 * <h3>Sample Factory Configuration</h3>
60 * <pre>
61 * <code>
62 * factory.invoker.servlet = org.apache.jetspeed.container.invoker.ServletPortletInvoker
63 * factory.invoker.servlet.pool.size = 50
64 * factory.invoker.servlet.mapping.name = /container
65 * </code>
66 * </pre>
67 * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
68 * @version $Id: ServletPortletInvoker.java 554827 2007-07-10 05:12:23Z taylor $
69 */
70 public class ServletPortletInvoker implements JetspeedPortletInvoker
71 {
72 private final static Log log = LogFactory.getLog(ServletPortletInvoker.class);
73
74 protected PortletFactory portletFactory;
75 protected ServletContext jetspeedContext;
76 protected ServletConfig jetspeedConfig;
77 protected PortletDefinition portletDefinition;
78 protected boolean activated = false;
79 protected String servletMappingName;
80
81
82
83
84
85
86 public void passivate()
87 {
88 activated = false;
89 }
90
91
92
93
94 public boolean isActivated()
95 {
96 return activated;
97 }
98
99
100
101
102 public void activate(PortletFactory portletFactory, PortletDefinition portletDefinition, ServletConfig servletConfig)
103 {
104 this.portletFactory = portletFactory;
105 this.jetspeedConfig = servletConfig;
106 jetspeedContext = servletConfig.getServletContext();
107 this.portletDefinition = portletDefinition;
108 activated = true;
109 }
110
111
112
113
114 public void activate(PortletFactory portletFactory, PortletDefinition portletDefinition, ServletConfig servletConfig, String servletMappingName)
115 {
116 this.servletMappingName = servletMappingName;
117 activate(portletFactory, portletDefinition, servletConfig);
118 }
119
120 /***
121 *
122 * @param request
123 * @param response
124 * @throws PortletException
125 */
126 public void render(RenderRequest request, RenderResponse response) throws PortletException, IOException
127 {
128 invoke(request, response, ContainerConstants.METHOD_RENDER);
129 }
130
131 /***
132 *
133 */
134 public void action(ActionRequest request, ActionResponse response) throws PortletException, IOException
135 {
136 invoke(request, response, ContainerConstants.METHOD_ACTION);
137 }
138
139 /***
140 *
141 */
142 public void load(PortletRequest request, RenderResponse response) throws PortletException
143 {
144 try
145 {
146 invoke(request, response, ContainerConstants.METHOD_NOOP);
147 }
148 catch (IOException e)
149 {
150 log.error("ServletPortletInvokerImpl.load() - Error while dispatching portlet.", e);
151 throw new PortletException(e);
152 }
153 }
154
155 /***
156 * Creates a servlet request dispatcher to dispatch to another web application to render the portlet.
157 * NOTE: this method requires that your container supports cross-context dispatching.
158 * Cross-context dispatching is known to work on Tomcat, Catalina, Tomcat-5.
159 *
160 * @param portletRequest
161 * @param portletResponse
162 * @param methodID
163 * @throws PortletException
164 * @throws IOException
165 */
166 protected void invoke(PortletRequest portletRequest, PortletResponse portletResponse, Integer methodID)
167 throws PortletException, IOException
168 {
169
170
171 PortletDefinition portletDefinition = null;
172
173
174
175 boolean isParallelMode = (Thread.currentThread() instanceof Worker || CurrentWorkerContext.getCurrentWorkerContextUsed());
176
177 if (isParallelMode)
178 {
179 portletDefinition = (PortletDefinition) CurrentWorkerContext.getAttribute(PortalReservedParameters.PORTLET_DEFINITION_ATTRIBUTE);
180 }
181
182 if (portletDefinition == null)
183 {
184 portletDefinition = this.portletDefinition;
185 }
186
187 MutablePortletApplication app = (MutablePortletApplication)portletDefinition.getPortletApplicationDefinition();
188
189 WebApplicationDefinition webApplicationDefinition = app.getWebApplicationDefinition();
190 if(webApplicationDefinition == null)
191 {
192 throw new IllegalStateException("Portlet application "+app.getName()+ " has no associated web application.");
193 }
194 String portletApplicationName = webApplicationDefinition.getContextRoot();
195
196
197 ServletRequest servletRequest = ((HttpServletRequestWrapper)((HttpServletRequestWrapper)((HttpServletRequestWrapper)portletRequest).getRequest()).getRequest()).getRequest();
198
199 ServletResponse servletResponse = ((HttpServletResponseWrapper) portletResponse).getResponse();
200
201 ServletContext appContext = jetspeedContext.getContext(portletApplicationName);
202 if (null == appContext)
203 {
204 String message = "Failed to find Servlet context for Portlet Application: " + portletApplicationName;
205 log.error(message);
206 throw new PortletException(message);
207 }
208 PortletInstance portletInstance = portletFactory.getPortletInstance(appContext, portletDefinition);
209 RequestDispatcher dispatcher = appContext.getRequestDispatcher(servletMappingName);
210 if (null == dispatcher)
211 {
212 String message =
213 "Failed to get Request Dispatcher for Portlet Application: "
214 + portletApplicationName
215 + ", servlet: "
216 + servletMappingName;
217 log.error(message);
218 throw new PortletException(message);
219 }
220
221 try
222 {
223 servletRequest.setAttribute(ContainerConstants.PORTLET, portletInstance);
224 servletRequest.setAttribute(ContainerConstants.PORTLET_CONFIG, portletInstance.getConfig());
225 servletRequest.setAttribute(ContainerConstants.PORTLET_REQUEST, portletRequest);
226 servletRequest.setAttribute(ContainerConstants.PORTLET_RESPONSE, portletResponse);
227 servletRequest.setAttribute(ContainerConstants.METHOD_ID, methodID);
228 servletRequest.setAttribute(ContainerConstants.PORTLET_NAME, app.getName()+"::"+portletDefinition.getName());
229 RequestContext requestContext = (RequestContext)servletRequest.getAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE);
230 servletRequest.setAttribute(ContainerConstants.PORTAL_CONTEXT, requestContext.getRequest().getContextPath());
231
232
233 if (isParallelMode)
234 {
235 CurrentWorkerContext.setAttribute(ContainerConstants.PORTLET, portletInstance);
236 CurrentWorkerContext.setAttribute(ContainerConstants.PORTLET_CONFIG, portletInstance.getConfig());
237 CurrentWorkerContext.setAttribute(ContainerConstants.PORTLET_REQUEST, portletRequest);
238 CurrentWorkerContext.setAttribute(ContainerConstants.PORTLET_RESPONSE, portletResponse);
239 CurrentWorkerContext.setAttribute(ContainerConstants.METHOD_ID, methodID);
240 CurrentWorkerContext.setAttribute(ContainerConstants.PORTLET_NAME, app.getName()+"::"+portletDefinition.getName());
241 CurrentWorkerContext.setAttribute(ContainerConstants.PORTAL_CONTEXT, requestContext.getRequest().getContextPath());
242 }
243
244 PortletRequestContext.createContext(portletDefinition, portletInstance, portletRequest, portletResponse);
245 dispatcher.include(servletRequest, servletResponse);
246
247 }
248 catch (Exception e)
249 {
250 String message =
251 "Failed to dispatch.include for Portlet Application: " + portletApplicationName + ", servlet: " + servletMappingName;
252 log.error(message, e);
253 throw new PortletException(message, e);
254 }
255 finally
256 {
257 PortletRequestContext.clearContext();
258
259
260 if (isParallelMode)
261 {
262 CurrentWorkerContext.removeAttribute(ContainerConstants.PORTLET);
263 CurrentWorkerContext.removeAttribute(ContainerConstants.PORTLET_CONFIG);
264 CurrentWorkerContext.removeAttribute(ContainerConstants.PORTLET_REQUEST);
265 CurrentWorkerContext.removeAttribute(ContainerConstants.PORTLET_RESPONSE);
266 CurrentWorkerContext.removeAttribute(ContainerConstants.METHOD_ID);
267 CurrentWorkerContext.removeAttribute(ContainerConstants.PORTLET_NAME);
268 CurrentWorkerContext.removeAttribute(ContainerConstants.PORTAL_CONTEXT);
269 }
270
271 servletRequest.removeAttribute(ContainerConstants.PORTLET);
272 servletRequest.removeAttribute(ContainerConstants.PORTLET_CONFIG);
273 servletRequest.removeAttribute(ContainerConstants.PORTLET_REQUEST);
274 servletRequest.removeAttribute(ContainerConstants.PORTLET_RESPONSE);
275 servletRequest.removeAttribute(ContainerConstants.METHOD_ID);
276 servletRequest.removeAttribute(ContainerConstants.PORTLET_NAME);
277 servletRequest.removeAttribute(ContainerConstants.PORTAL_CONTEXT);
278 }
279
280 }
281
282 }