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;
018:
019: import java.io.File;
020: import java.io.IOException;
021: import java.io.OutputStreamWriter;
022: import java.io.PrintWriter;
023: import java.io.StringWriter;
024: import java.util.Timer;
025: import java.util.TimerTask;
026:
027: import javax.portlet.ActionRequest;
028: import javax.portlet.ActionResponse;
029: import javax.portlet.Portlet;
030: import javax.portlet.RenderRequest;
031: import javax.portlet.RenderResponse;
032: import javax.portlet.UnavailableException;
033: import javax.servlet.RequestDispatcher;
034: import javax.servlet.ServletConfig;
035: import javax.servlet.ServletContext;
036: import javax.servlet.ServletException;
037: import javax.servlet.http.HttpServlet;
038: import javax.servlet.http.HttpServletRequest;
039: import javax.servlet.http.HttpServletRequestWrapper;
040: import javax.servlet.http.HttpServletResponse;
041:
042: import org.apache.jetspeed.container.session.PortalSessionsManager;
043: import org.apache.jetspeed.request.RequestContext;
044: import org.apache.jetspeed.services.JetspeedPortletServices;
045: import org.apache.jetspeed.services.PortletServices;
046: import org.apache.jetspeed.tools.pamanager.PortletApplicationManagement;
047: import org.apache.jetspeed.util.DirectoryHelper;
048: import org.apache.jetspeed.aggregator.CurrentWorkerContext;
049:
050: /**
051: * Jetspeed Container entry point.
052: *
053: * @author <a href="mailto:david@bluesunrise.com">David Sean Taylor</a>
054: * @version $Id: JetspeedContainerServlet.java 593180 2007-11-08 15:00:35Z weaver $
055: */
056: public class JetspeedContainerServlet extends HttpServlet {
057: private String contextName;
058: private boolean started = false;
059: private Timer startTimer = null;
060: private PortalSessionsManager psm;
061: private String contextPath;
062:
063: // -------------------------------------------------------------------
064: // I N I T I A L I Z A T I O N
065: // -------------------------------------------------------------------
066: private static final String JCS = "JetspeedContainerServlet: ";
067: private static final String INIT_START_MSG = JCS
068: + "starting initialization of Portlet Application at: ";
069: private static final String TRY_START_MSG = JCS
070: + "attemping to start Portlet Application at: ";
071: private static final String STARTED_MSG = JCS
072: + "started Portlet Application at: ";
073: private static final String INIT_FAILED_MSG = JCS
074: + "initialization failed for Portlet Application at: ";
075: private static final String INIT_DONE_MSG = JCS
076: + "initialization done for Portlet Application at: ";
077: private static final String STOP_MSG = JCS
078: + "shutting down portlet application at: ";
079: private static final String STOP_FAILED_MSG = JCS
080: + "shutting down error for portlet application at: ";
081:
082: public synchronized final void init(ServletConfig config)
083: throws ServletException {
084: synchronized (this .getClass()) {
085: super .init(config);
086:
087: ServletContext context = getServletContext();
088:
089: started = false;
090: startTimer = null;
091: contextName = config.getInitParameter("contextName");
092: contextPath = config.getInitParameter("contextPath");
093:
094: if (null == contextName || contextName.length() == 0) {
095: contextName = null; // just to make sure for the destroy method
096:
097: throw new ServletException(
098: JCS
099: + "Portlet Application contextName not supplied in Init Parameters.");
100: }
101:
102: if (null == contextPath || contextPath.length() == 0) {
103: contextPath = "/" + contextName;
104: } else if (!contextPath.startsWith("/")) {
105: throw new ServletException(
106: JCS
107: + "Portlet Application contextPath must start with a \"/\".");
108: }
109:
110: String paDir = context.getRealPath("/");
111: if (paDir == null) {
112: throw new ServletException(
113: JCS
114: + " Initialization of PortletApplication at "
115: + contextName
116: + " without access to its real path not supported");
117: }
118:
119: context.log(INIT_START_MSG + contextName);
120: System.out.println(INIT_START_MSG + contextName);
121:
122: try {
123: startPortletApplication(context, paDir, Thread
124: .currentThread().getContextClassLoader());
125: } catch (Exception e) {
126: String message = INIT_FAILED_MSG + contextName;
127: context.log(message, e);
128: System.err.println(message);
129: throw new ServletException(message, e);
130: }
131:
132: context.log(INIT_DONE_MSG + contextName);
133: System.out.println(INIT_DONE_MSG + contextName);
134: }
135: }
136:
137: private void startPortletApplication(final ServletContext context,
138: final String paDir, final ClassLoader paClassLoader)
139: throws ServletException {
140:
141: /* TODO: Ate Douma, 2005-03-25
142: Under fusion, this call always results in a javax.naming.NameNotFoundException: "Name jdbc is not bound in this Context"
143: but when started from a separate (timer) Thread, even with only a delay of 1ms, it works again.
144: I don't have any clue what is the cause of this or how to solve it, thus for now I disabled starting directly
145:
146: if (attemptStart(context, contextName, paDir, paClassLoader))
147: {
148: started = true;
149: return;
150: }
151: */
152: final String START_DELAYED_MSG = JCS
153: + "Could not yet start portlet application at: "
154: + contextName
155: + ". Starting back ground thread to start when the portal comes online.";
156: context.log(START_DELAYED_MSG);
157: startTimer = new Timer(true);
158: startTimer.schedule(new TimerTask() {
159: public void run() {
160: synchronized (contextName) {
161: if (startTimer != null) {
162: if (attemptStart(context, contextName,
163: contextPath, paDir, paClassLoader)) {
164: startTimer.cancel();
165: startTimer = null;
166: } else {
167: context.log(START_DELAYED_MSG);
168: }
169: }
170: }
171: }
172: },
173: // 10000, Setting delay to 1ms, see TODO comment above
174: 1, 10000);
175: }
176:
177: private boolean attemptStart(ServletContext context,
178: String contextName, String contextPath, String paDir,
179: ClassLoader paClassLoader) {
180: try {
181: context.log(TRY_START_MSG + contextPath);
182: PortletServices services = JetspeedPortletServices
183: .getSingleton();
184: if (services != null) {
185: PortletApplicationManagement pam = (PortletApplicationManagement) services
186: .getService("PAM");
187:
188: if (pam != null && pam.isStarted()) {
189: DirectoryHelper paDirHelper = new DirectoryHelper(
190: new File(paDir));
191: pam.startPortletApplication(contextName,
192: contextPath, paDirHelper, paClassLoader);
193: started = true;
194: psm = (PortalSessionsManager) services
195: .getService(PortalSessionsManager.SERVICE_NAME);
196:
197: context.log(STARTED_MSG + contextPath);
198: return true;
199: }
200: }
201: } catch (Exception e) {
202: context.log(INIT_FAILED_MSG + contextPath, e);
203: return true; // don't try again
204: }
205: return false;
206: }
207:
208: // -------------------------------------------------------------------
209: // R E Q U E S T P R O C E S S I N G
210: // -------------------------------------------------------------------
211:
212: /**
213: * The primary method invoked when the Jetspeed servlet is executed.
214: *
215: * @param request Servlet request.
216: * @param ressponse Servlet response.
217: * @exception IOException a servlet exception.
218: * @exception ServletException a servlet exception.
219: */
220: public final void doGet(HttpServletRequest request,
221: HttpServletResponse response) throws IOException,
222: ServletException {
223: String portletName = null;
224: Integer method = ContainerConstants.METHOD_NOOP;
225: Portlet portlet = null;
226: boolean destroyPortlet = false;
227: boolean isParallelMode = false;
228:
229: try {
230: isParallelMode = CurrentWorkerContext
231: .getParallelRenderingMode();
232:
233: if (isParallelMode) {
234: method = (Integer) CurrentWorkerContext
235: .getAttribute(ContainerConstants.METHOD_ID);
236: } else {
237: method = (Integer) request
238: .getAttribute(ContainerConstants.METHOD_ID);
239: }
240: if (method == ContainerConstants.METHOD_NOOP) {
241: return;
242: }
243: if (isParallelMode) {
244: portlet = (Portlet) CurrentWorkerContext
245: .getAttribute(ContainerConstants.PORTLET);
246: portletName = (String) CurrentWorkerContext
247: .getAttribute(ContainerConstants.PORTLET_NAME);
248: } else {
249: portlet = (Portlet) request
250: .getAttribute(ContainerConstants.PORTLET);
251: portletName = (String) request
252: .getAttribute(ContainerConstants.PORTLET_NAME);
253: request.removeAttribute(ContainerConstants.PORTLET);
254: }
255:
256: if (method == ContainerConstants.METHOD_ACTION) {
257: ActionRequest actionRequest = (ActionRequest) request
258: .getAttribute(ContainerConstants.PORTLET_REQUEST);
259: ActionResponse actionResponse = (ActionResponse) request
260: .getAttribute(ContainerConstants.PORTLET_RESPONSE);
261: // inject the current request into the actionRequest handler (o.a.j.engine.servlet.ServletRequestImpl)
262: ((HttpServletRequestWrapper) ((HttpServletRequestWrapper) actionRequest)
263: .getRequest()).setRequest(request);
264:
265: portlet.processAction(actionRequest, actionResponse);
266: } else if (method == ContainerConstants.METHOD_RENDER) {
267: RenderRequest renderRequest = null;
268: RenderResponse renderResponse = null;
269:
270: if (isParallelMode) {
271: renderRequest = (RenderRequest) CurrentWorkerContext
272: .getAttribute(ContainerConstants.PORTLET_REQUEST);
273: renderResponse = (RenderResponse) CurrentWorkerContext
274: .getAttribute(ContainerConstants.PORTLET_RESPONSE);
275: } else {
276: renderRequest = (RenderRequest) request
277: .getAttribute(ContainerConstants.PORTLET_REQUEST);
278: renderResponse = (RenderResponse) request
279: .getAttribute(ContainerConstants.PORTLET_RESPONSE);
280: }
281: // inject the current request into the renderRequest handler (o.a.j.engine.servlet.ServletRequestImpl)
282: ((HttpServletRequestWrapper) ((HttpServletRequestWrapper) renderRequest)
283: .getRequest()).setRequest(request);
284: portlet.render(renderRequest, renderResponse);
285: }
286:
287: // if we get this far we are home free
288: return;
289: } catch (Throwable t) {
290: if (t instanceof UnavailableException) {
291: // destroy the portlet in the finally clause
292: destroyPortlet = true;
293: }
294:
295: if (method != ContainerConstants.METHOD_ACTION) {
296: ServletContext context = getServletContext();
297: context.log(JCS + "Error rendering portlet \""
298: + portletName + "\": " + t.toString(), t);
299: try {
300: String errorTemplate = getInitParameter("portal.error.page");
301: if (errorTemplate == null) {
302: errorTemplate = "/WEB-INF/templates/generic/html/error.vm";
303: }
304: if (null != context.getResource(errorTemplate)) {
305: RequestDispatcher dispatcher = getServletContext()
306: .getRequestDispatcher(errorTemplate);
307: request.setAttribute("e", t);
308: StringWriter stackTrace = new StringWriter();
309: t.printStackTrace(new PrintWriter(stackTrace));
310: request.setAttribute("stacktrace", stackTrace
311: .toString());
312: dispatcher.include(request, response);
313: } else {
314: displayPortletNotAvailableMessage(t, response,
315: portletName);
316: }
317: } catch (Throwable e) {
318: displayPortletNotAvailableMessage(t, response,
319: portletName);
320: } finally {
321: t.printStackTrace();
322: }
323: } else {
324: if (t instanceof RuntimeException) {
325: throw (RuntimeException) t;
326: } else if (t instanceof IOException) {
327: throw (IOException) t;
328: } else if (t instanceof ServletException) {
329: throw (ServletException) t;
330: } else {
331: throw new ServletException(t);
332: }
333: }
334: } finally {
335: if (destroyPortlet) {
336: // portlet throwed UnavailableException: take it out of service
337: try {
338: portlet.destroy();
339: } catch (Exception e) {
340: // never mind, it won't be used anymore.
341: }
342: }
343: if (psm != null) {
344: RequestContext rc = (RequestContext) request
345: .getAttribute(RequestContext.REQUEST_PORTALENV);
346: psm.checkMonitorSession(contextName, rc.getRequest()
347: .getSession(), request.getSession(false));
348: }
349: }
350: }
351:
352: private void displayPortletNotAvailableMessage(Throwable t,
353: HttpServletResponse response, String portletName)
354: throws IOException {
355: getServletContext()
356: .log(
357: JCS
358: + "Error rendering JetspeedContainerServlet error page: "
359: + t.toString(), t);
360: PrintWriter directError;
361: try {
362: directError = new PrintWriter(response.getWriter());
363: } catch (IllegalStateException e) {
364: // Happens if get writer is already been called.
365: directError = new PrintWriter(new OutputStreamWriter(
366: response.getOutputStream()));
367: }
368: directError.write("Portlet is Not Available: " + portletName
369: + "<br/>Reason: " + t.getMessage());
370: //t.printStackTrace(directError);
371: directError.close();
372: }
373:
374: /**
375: * In this application doGet and doPost are the same thing.
376: *
377: * @param req Servlet request.
378: * @param res Servlet response.
379: * @exception IOException a servlet exception.
380: * @exception ServletException a servlet exception.
381: */
382: public final void doPost(HttpServletRequest req,
383: HttpServletResponse res) throws IOException,
384: ServletException {
385: doGet(req, res);
386: }
387:
388: // -------------------------------------------------------------------
389: // S E R V L E T S H U T D O W N
390: // -------------------------------------------------------------------
391:
392: public final void destroy() {
393: if (contextName != null) {
394: synchronized (contextName) {
395: if (startTimer != null) {
396: startTimer.cancel();
397: startTimer = null;
398: } else if (started) {
399: started = false;
400: PortletServices services = JetspeedPortletServices
401: .getSingleton();
402: if (services != null) {
403: PortletApplicationManagement pam = (PortletApplicationManagement) services
404: .getService("PAM");
405:
406: if (pam != null) {
407: getServletContext().log(
408: STOP_MSG + contextName);
409: try {
410: pam.stopPortletApplication(contextName);
411: } catch (Exception e) {
412: getServletContext().log(
413: STOP_FAILED_MSG + contextName,
414: e);
415: }
416: }
417: }
418: contextName = null;
419: psm = null;
420: }
421: }
422: }
423: }
424: }
|