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