001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.container.invoker;
018:
019: import java.io.IOException;
020:
021: import javax.portlet.ActionRequest;
022: import javax.portlet.ActionResponse;
023: import javax.portlet.PortletException;
024: import javax.portlet.PortletRequest;
025: import javax.portlet.PortletResponse;
026: import javax.portlet.RenderRequest;
027: import javax.portlet.RenderResponse;
028: import javax.servlet.RequestDispatcher;
029: import javax.servlet.ServletConfig;
030: import javax.servlet.ServletContext;
031: import javax.servlet.ServletRequest;
032: import javax.servlet.ServletResponse;
033: import javax.servlet.http.HttpServletRequest;
034:
035: import org.apache.commons.logging.Log;
036: import org.apache.commons.logging.LogFactory;
037: import org.apache.jetspeed.PortalReservedParameters;
038: import org.apache.jetspeed.container.ContainerConstants;
039: import org.apache.jetspeed.container.PortletRequestContext;
040: import org.apache.jetspeed.factory.PortletFactory;
041: import org.apache.jetspeed.factory.PortletInstance;
042: import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
043: import org.apache.jetspeed.request.RequestContext;
044: import org.apache.jetspeed.aggregator.CurrentWorkerContext;
045: import org.apache.pluto.om.portlet.PortletDefinition;
046: import org.apache.pluto.om.servlet.WebApplicationDefinition;
047:
048: /**
049: * ServletPortletInvoker invokes portlets in another web application, calling a
050: * portlet's render or action method via a cross context request dispatcher.
051: * In order for this class to work, a servlet must be special servlet must be
052: * infused into the web (portlet) application. This servlet knows how to delegate
053: * to portlets and package their response back into a servlet response.
054: * The context name of the servlet should be configurable. The default context name is "/container"
055: * ServletPortletInvokerFactory is the factory for creating portlet invokers that
056: * use Jetspeed Container servlet.
057: * <h3>Sample Factory Configuration</h3>
058: * <pre>
059: * <code>
060: * factory.invoker.servlet = org.apache.jetspeed.container.invoker.ServletPortletInvoker
061: * factory.invoker.servlet.pool.size = 50
062: * factory.invoker.servlet.mapping.name = /container
063: * </code>
064: * </pre>
065: * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
066: * @version $Id: ServletPortletInvoker.java 598155 2007-11-26 07:41:26Z woonsan $
067: */
068: public class ServletPortletInvoker implements JetspeedPortletInvoker {
069: private final static Log log = LogFactory
070: .getLog(ServletPortletInvoker.class);
071:
072: protected PortletFactory portletFactory;
073: protected ServletContext jetspeedContext;
074: protected ServletConfig jetspeedConfig;
075: protected PortletDefinition portletDefinition;
076: protected boolean activated = false;
077: protected String servletMappingName;
078:
079: /**
080: * requestResponseUnwrapper used to unwrap portlet request or portlet response
081: * to find the real servlet request or servlet response.
082: */
083: protected PortletRequestResponseUnwrapper requestResponseUnwrapper;
084:
085: public ServletPortletInvoker() {
086: this (new DefaultPortletRequestResponseUnwrapper());
087: }
088:
089: public ServletPortletInvoker(
090: PortletRequestResponseUnwrapper requestResponseUnwrapper) {
091: this .requestResponseUnwrapper = requestResponseUnwrapper;
092: }
093:
094: /* (non-Javadoc)
095: * @see org.apache.jetspeed.container.invoker.JetspeedPortletInvoker#passivate()
096: */
097: public void passivate() {
098: activated = false;
099: }
100:
101: /* (non-Javadoc)
102: * @see org.apache.jetspeed.container.invoker.JetspeedPortletInvoker#isActivated()
103: */
104: public boolean isActivated() {
105: return activated;
106: }
107:
108: /* (non-Javadoc)
109: * @see org.apache.jetspeed.container.invoker.JetspeedPortletInvoker#activate(PortletFactory,org.apache.pluto.om.portlet.PortletDefinition, javax.servlet.ServletConfig)
110: */
111: public void activate(PortletFactory portletFactory,
112: PortletDefinition portletDefinition,
113: ServletConfig servletConfig) {
114: this .portletFactory = portletFactory;
115: this .jetspeedConfig = servletConfig;
116: jetspeedContext = servletConfig.getServletContext();
117: this .portletDefinition = portletDefinition;
118: activated = true;
119: }
120:
121: /* (non-Javadoc)
122: * @see org.apache.jetspeed.container.invoker.JetspeedPortletInvoker#activate(PortletFactory,org.apache.pluto.om.portlet.PortletDefinition, javax.servlet.ServletConfig, java.lang.String)
123: */
124: public void activate(PortletFactory portletFactory,
125: PortletDefinition portletDefinition,
126: ServletConfig servletConfig, String servletMappingName) {
127: this .servletMappingName = servletMappingName;
128: activate(portletFactory, portletDefinition, servletConfig);
129: }
130:
131: /**
132: *
133: * @param request
134: * @param response
135: * @throws PortletException
136: */
137: public void render(RenderRequest request, RenderResponse response)
138: throws PortletException, IOException {
139: invoke(request, response, ContainerConstants.METHOD_RENDER);
140: }
141:
142: /**
143: *
144: */
145: public void action(ActionRequest request, ActionResponse response)
146: throws PortletException, IOException {
147: invoke(request, response, ContainerConstants.METHOD_ACTION);
148: }
149:
150: /**
151: *
152: */
153: public void load(PortletRequest request, RenderResponse response)
154: throws PortletException {
155: try {
156: invoke(request, response, ContainerConstants.METHOD_NOOP);
157: } catch (IOException e) {
158: log
159: .error(
160: "ServletPortletInvokerImpl.load() - Error while dispatching portlet.",
161: e);
162: throw new PortletException(e);
163: }
164: }
165:
166: /**
167: * Creates a servlet request dispatcher to dispatch to another web application to render the portlet.
168: * NOTE: this method requires that your container supports cross-context dispatching.
169: * Cross-context dispatching is known to work on Tomcat, Catalina, Tomcat-5.
170: *
171: * @param portletRequest
172: * @param portletResponse
173: * @param methodID
174: * @throws PortletException
175: * @throws IOException
176: */
177: protected void invoke(PortletRequest portletRequest,
178: PortletResponse portletResponse, Integer methodID)
179: throws PortletException, IOException {
180: // In case of parallel mode, the portletDefinition member is not thread-safe.
181: // So, hide the member variable by the following local variable.
182: PortletDefinition portletDefinition = null;
183:
184: // In case of parallel mode, get portlet definition object from the worker thread context.
185: // Otherwise, refer the member variable.
186: boolean isParallelMode = CurrentWorkerContext
187: .getParallelRenderingMode();
188:
189: if (isParallelMode) {
190: portletDefinition = (PortletDefinition) CurrentWorkerContext
191: .getAttribute(PortalReservedParameters.PORTLET_DEFINITION_ATTRIBUTE);
192: }
193:
194: if (portletDefinition == null) {
195: portletDefinition = this .portletDefinition;
196: }
197:
198: MutablePortletApplication app = (MutablePortletApplication) portletDefinition
199: .getPortletApplicationDefinition();
200:
201: WebApplicationDefinition webApplicationDefinition = app
202: .getWebApplicationDefinition();
203: if (webApplicationDefinition == null) {
204: throw new IllegalStateException("Portlet application "
205: + app.getName()
206: + " has no associated web application.");
207: }
208: String portletApplicationName = webApplicationDefinition
209: .getContextRoot();
210:
211: ServletContext appContext = jetspeedContext
212: .getContext(portletApplicationName);
213: if (null == appContext) {
214: String message = "Failed to find Servlet context for Portlet Application: "
215: + portletApplicationName;
216: log.error(message);
217: throw new PortletException(message);
218: }
219: PortletInstance portletInstance = portletFactory
220: .getPortletInstance(appContext, portletDefinition);
221: RequestDispatcher dispatcher = appContext
222: .getRequestDispatcher(servletMappingName);
223: if (null == dispatcher) {
224: String message = "Failed to get Request Dispatcher for Portlet Application: "
225: + portletApplicationName
226: + ", servlet: "
227: + servletMappingName;
228: log.error(message);
229: throw new PortletException(message);
230: }
231:
232: // gather all required data from request and response
233: ServletRequest servletRequest = this .requestResponseUnwrapper
234: .unwrapPortletRequest(portletRequest);
235: ServletResponse servletResponse = this .requestResponseUnwrapper
236: .unwrapPortletResponse(portletResponse);
237:
238: try {
239: RequestContext requestContext = (RequestContext) servletRequest
240: .getAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE);
241:
242: if (isParallelMode) {
243: synchronized (servletRequest) {
244: servletRequest
245: .setAttribute(ContainerConstants.PORTLET,
246: portletInstance);
247: servletRequest.setAttribute(
248: ContainerConstants.PORTLET_CONFIG,
249: portletInstance.getConfig());
250: servletRequest.setAttribute(
251: ContainerConstants.PORTLET_REQUEST,
252: portletRequest);
253: servletRequest.setAttribute(
254: ContainerConstants.PORTLET_RESPONSE,
255: portletResponse);
256: servletRequest.setAttribute(
257: ContainerConstants.METHOD_ID, methodID);
258: servletRequest.setAttribute(
259: ContainerConstants.PORTLET_NAME, app
260: .getName()
261: + "::"
262: + portletDefinition.getName());
263: servletRequest.setAttribute(
264: ContainerConstants.PORTAL_CONTEXT,
265: ((HttpServletRequest) servletRequest)
266: .getContextPath());
267: }
268: } else {
269: servletRequest.setAttribute(ContainerConstants.PORTLET,
270: portletInstance);
271: servletRequest.setAttribute(
272: ContainerConstants.PORTLET_CONFIG,
273: portletInstance.getConfig());
274: servletRequest.setAttribute(
275: ContainerConstants.PORTLET_REQUEST,
276: portletRequest);
277: servletRequest.setAttribute(
278: ContainerConstants.PORTLET_RESPONSE,
279: portletResponse);
280: servletRequest.setAttribute(
281: ContainerConstants.METHOD_ID, methodID);
282: servletRequest.setAttribute(
283: ContainerConstants.PORTLET_NAME, app.getName()
284: + "::" + portletDefinition.getName());
285: servletRequest.setAttribute(
286: ContainerConstants.PORTAL_CONTEXT,
287: requestContext.getRequest().getContextPath());
288: }
289:
290: // Store same request attributes into the worker in parallel mode.
291: if (isParallelMode) {
292: CurrentWorkerContext.setAttribute(
293: ContainerConstants.PORTLET, portletInstance);
294: CurrentWorkerContext.setAttribute(
295: ContainerConstants.PORTLET_CONFIG,
296: portletInstance.getConfig());
297: CurrentWorkerContext.setAttribute(
298: ContainerConstants.PORTLET_REQUEST,
299: portletRequest);
300: CurrentWorkerContext.setAttribute(
301: ContainerConstants.PORTLET_RESPONSE,
302: portletResponse);
303: CurrentWorkerContext.setAttribute(
304: ContainerConstants.METHOD_ID, methodID);
305: CurrentWorkerContext.setAttribute(
306: ContainerConstants.PORTLET_NAME, app.getName()
307: + "::" + portletDefinition.getName());
308: CurrentWorkerContext.setAttribute(
309: ContainerConstants.PORTAL_CONTEXT,
310: ((HttpServletRequest) servletRequest)
311: .getContextPath());
312: }
313:
314: PortletRequestContext.createContext(portletDefinition,
315: portletInstance, portletRequest, portletResponse);
316: dispatcher.include(servletRequest, servletResponse);
317:
318: } catch (Exception e) {
319: String message = "Failed to dispatch.include for Portlet Application: "
320: + portletApplicationName
321: + ", servlet: "
322: + servletMappingName;
323: log.error(message, e);
324: throw new PortletException(message, e);
325: } finally {
326: PortletRequestContext.clearContext();
327:
328: // In parallel mode, remove all attributes of worker context.
329: if (isParallelMode) {
330: CurrentWorkerContext
331: .removeAttribute(ContainerConstants.PORTLET);
332: CurrentWorkerContext
333: .removeAttribute(ContainerConstants.PORTLET_CONFIG);
334: CurrentWorkerContext
335: .removeAttribute(ContainerConstants.PORTLET_REQUEST);
336: CurrentWorkerContext
337: .removeAttribute(ContainerConstants.PORTLET_RESPONSE);
338: CurrentWorkerContext
339: .removeAttribute(ContainerConstants.METHOD_ID);
340: CurrentWorkerContext
341: .removeAttribute(ContainerConstants.PORTLET_NAME);
342: CurrentWorkerContext
343: .removeAttribute(ContainerConstants.PORTAL_CONTEXT);
344: }
345:
346: servletRequest.removeAttribute(ContainerConstants.PORTLET);
347: servletRequest
348: .removeAttribute(ContainerConstants.PORTLET_CONFIG);
349: servletRequest
350: .removeAttribute(ContainerConstants.PORTLET_REQUEST);
351: servletRequest
352: .removeAttribute(ContainerConstants.PORTLET_RESPONSE);
353: servletRequest
354: .removeAttribute(ContainerConstants.METHOD_ID);
355: servletRequest
356: .removeAttribute(ContainerConstants.PORTLET_NAME);
357: servletRequest
358: .removeAttribute(ContainerConstants.PORTAL_CONTEXT);
359: }
360:
361: }
362:
363: }
|