View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.container;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.OutputStreamWriter;
22  import java.io.PrintWriter;
23  import java.io.StringWriter;
24  import java.util.Timer;
25  import java.util.TimerTask;
26  
27  import javax.portlet.ActionRequest;
28  import javax.portlet.ActionResponse;
29  import javax.portlet.Portlet;
30  import javax.portlet.RenderRequest;
31  import javax.portlet.RenderResponse;
32  import javax.portlet.UnavailableException;
33  import javax.servlet.RequestDispatcher;
34  import javax.servlet.ServletConfig;
35  import javax.servlet.ServletContext;
36  import javax.servlet.ServletException;
37  import javax.servlet.http.HttpServlet;
38  import javax.servlet.http.HttpServletRequest;
39  import javax.servlet.http.HttpServletRequestWrapper;
40  import javax.servlet.http.HttpServletResponse;
41  
42  import org.apache.jetspeed.container.session.PortalSessionsManager;
43  import org.apache.jetspeed.request.RequestContext;
44  import org.apache.jetspeed.services.JetspeedPortletServices;
45  import org.apache.jetspeed.services.PortletServices;
46  import org.apache.jetspeed.tools.pamanager.PortletApplicationManagement;
47  import org.apache.jetspeed.util.DirectoryHelper;
48  import org.apache.jetspeed.aggregator.CurrentWorkerContext;
49  
50  /***
51   * Jetspeed Container entry point.
52   *
53   * @author <a href="mailto:david@bluesunrise.com">David Sean Taylor</a>
54   * @version $Id: JetspeedContainerServlet.java 593180 2007-11-08 15:00:35Z weaver $
55   */
56  public class JetspeedContainerServlet extends HttpServlet 
57  {
58      private String  contextName;
59      private boolean started = false;
60      private Timer   startTimer = null;
61      private PortalSessionsManager psm;
62      private String contextPath;
63  
64      // -------------------------------------------------------------------
65      // I N I T I A L I Z A T I O N
66      // -------------------------------------------------------------------
67      private static final String JCS = "JetspeedContainerServlet: ";
68      private static final String INIT_START_MSG = JCS + "starting initialization of Portlet Application at: ";
69      private static final String TRY_START_MSG = JCS + "attemping to start Portlet Application at: ";
70      private static final String STARTED_MSG = JCS + "started Portlet Application at: ";
71      private static final String INIT_FAILED_MSG = JCS + "initialization failed for Portlet Application at: ";
72      private static final String INIT_DONE_MSG = JCS + "initialization done for Portlet Application at: ";
73      private static final String STOP_MSG = JCS + "shutting down portlet application at: ";
74      private static final String STOP_FAILED_MSG = JCS + "shutting down error for portlet application at: ";
75      
76      public synchronized final void init(ServletConfig config) throws ServletException
77      {
78          synchronized (this.getClass())
79          {            
80              super.init(config);
81              
82              ServletContext context = getServletContext();
83  
84              started = false;
85              startTimer = null;            
86              contextName = config.getInitParameter("contextName");            
87              contextPath = config.getInitParameter("contextPath");
88  
89              if (null == contextName || contextName.length() == 0)
90              {
91                  contextName = null; // just to make sure for the destroy method
92                  
93                  throw new ServletException(JCS + "Portlet Application contextName not supplied in Init Parameters.");
94              }
95              
96              if (null == contextPath || contextPath.length() == 0)
97              {
98                  contextPath = "/"+contextName;
99              }
100             else if(!contextPath.startsWith("/"))
101             {
102                 throw new ServletException(JCS + "Portlet Application contextPath must start with a  \"/\"."); 
103             }
104             
105             
106             String paDir = context.getRealPath("/");
107             if ( paDir == null )
108                 {
109               throw new ServletException(JCS + " Initialization of PortletApplication at "+contextName+" without access to its real path not supported");
110                 }
111 
112             context.log(INIT_START_MSG + contextName);            
113             System.out.println(INIT_START_MSG + contextName);            
114 
115             try
116             {                
117               startPortletApplication(context, paDir, Thread.currentThread().getContextClassLoader());
118             }
119             catch (Exception e)
120             {
121                 String message = INIT_FAILED_MSG + contextName;
122                 context.log(message, e);
123                 System.err.println(message);
124                 throw new ServletException(message, e);
125             }
126 
127             context.log(INIT_DONE_MSG + contextName);
128             System.out.println(INIT_DONE_MSG + contextName);
129         }
130     }
131 
132     private void startPortletApplication(final ServletContext context, final String paDir, final ClassLoader paClassLoader)
133     throws ServletException
134     {
135 
136 /* TODO: Ate Douma, 2005-03-25
137    Under fusion, this call always results in a javax.naming.NameNotFoundException: "Name jdbc is not bound in this Context"
138    but when started from a separate (timer) Thread, even with only a delay of 1ms, it works again.
139    I don't have any clue what is the cause of this or how to solve it, thus for now I disabled starting directly
140 
141         if (attemptStart(context, contextName, paDir, paClassLoader)) 
142         {
143           started = true;
144             return;
145         }
146 */
147         final String START_DELAYED_MSG = JCS + "Could not yet start portlet application at: "+contextName+". Starting back ground thread to start when the portal comes online.";
148         context.log(START_DELAYED_MSG);
149         startTimer = new Timer(true);
150         startTimer.schedule(
151                 new TimerTask() {
152                     public void run() {
153                       synchronized(contextName)
154                       {
155                         if (startTimer != null)
156                         {
157                           if (attemptStart(context, contextName, contextPath, paDir, paClassLoader)) {
158                             startTimer.cancel();
159                             startTimer = null;
160                         } else {
161                             context.log(START_DELAYED_MSG);
162                           }
163                         }
164                         }
165                     }
166                 },
167 //                10000, Setting delay to 1ms, see TODO comment above
168                 1,
169                 10000);
170     }
171 
172     private boolean attemptStart(ServletContext context, String contextName, String contextPath, String paDir, ClassLoader paClassLoader) 
173     {
174         try
175         {
176             context.log(TRY_START_MSG + contextPath);
177             PortletServices services = JetspeedPortletServices.getSingleton();
178             if (services != null)
179             {
180                 PortletApplicationManagement pam =
181                     (PortletApplicationManagement)services.getService("PAM");
182 
183                 if (pam != null && pam.isStarted())
184                 {
185                     DirectoryHelper paDirHelper = new DirectoryHelper(new File(paDir));
186                     pam.startPortletApplication(contextName, contextPath, paDirHelper, paClassLoader);
187                     started = true;
188                     psm = (PortalSessionsManager)services.getService(PortalSessionsManager.SERVICE_NAME);
189 
190                     context.log(STARTED_MSG + contextPath);
191                     return true;
192                 }
193             }
194         }
195         catch (Exception e)
196         {
197             context.log(INIT_FAILED_MSG + contextPath, e);
198             return true; // don't try again
199         }
200         return false;
201     }    
202     
203     // -------------------------------------------------------------------
204     // R E Q U E S T  P R O C E S S I N G
205     // -------------------------------------------------------------------
206 
207     /***
208      * The primary method invoked when the Jetspeed servlet is executed.
209      *
210      * @param request Servlet request.
211      * @param ressponse Servlet response.
212      * @exception IOException a servlet exception.
213      * @exception ServletException a servlet exception.
214      */
215     public final void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
216     {
217         String portletName = null;
218         Integer method = ContainerConstants.METHOD_NOOP;
219         Portlet portlet = null;
220         boolean destroyPortlet = false;
221         boolean isParallelMode = false;
222         
223         try
224         {
225             isParallelMode = CurrentWorkerContext.getParallelRenderingMode();
226 
227             if (isParallelMode)
228             {
229                 method = (Integer) CurrentWorkerContext.getAttribute(ContainerConstants.METHOD_ID);
230             }
231             else
232             {
233                 method = (Integer) request.getAttribute(ContainerConstants.METHOD_ID);
234             }
235             if (method == ContainerConstants.METHOD_NOOP)
236             {
237                 return;
238             }
239             if (isParallelMode)
240             {
241                 portlet = (Portlet) CurrentWorkerContext.getAttribute(ContainerConstants.PORTLET);
242                 portletName = (String) CurrentWorkerContext.getAttribute(ContainerConstants.PORTLET_NAME);
243             }
244             else
245             {
246                 portlet = (Portlet)request.getAttribute(ContainerConstants.PORTLET);
247                 portletName = (String)request.getAttribute(ContainerConstants.PORTLET_NAME);
248                 request.removeAttribute(ContainerConstants.PORTLET);
249             }
250 
251             if (method == ContainerConstants.METHOD_ACTION)
252             {
253                 ActionRequest actionRequest = (ActionRequest) request.getAttribute(ContainerConstants.PORTLET_REQUEST);
254                 ActionResponse actionResponse = (ActionResponse) request.getAttribute(ContainerConstants.PORTLET_RESPONSE);
255                 // inject the current request into the actionRequest handler (o.a.j.engine.servlet.ServletRequestImpl)
256                 ((HttpServletRequestWrapper)((HttpServletRequestWrapper)actionRequest).getRequest()).setRequest(request);
257 
258                 portlet.processAction(actionRequest, actionResponse);
259             }
260             else if (method == ContainerConstants.METHOD_RENDER)
261             {
262                 RenderRequest renderRequest = null;
263                 RenderResponse renderResponse =  null;
264 
265                 if (isParallelMode)
266                 {
267                     renderRequest = (RenderRequest) CurrentWorkerContext.getAttribute(ContainerConstants.PORTLET_REQUEST);
268                     renderResponse = (RenderResponse) CurrentWorkerContext.getAttribute(ContainerConstants.PORTLET_RESPONSE);
269                 }
270                 else
271                 {
272                     renderRequest = (RenderRequest) request.getAttribute(ContainerConstants.PORTLET_REQUEST);
273                     renderResponse = (RenderResponse) request.getAttribute(ContainerConstants.PORTLET_RESPONSE);
274                 }                
275                 // inject the current request into the renderRequest handler (o.a.j.engine.servlet.ServletRequestImpl)
276                 ((HttpServletRequestWrapper)((HttpServletRequestWrapper)renderRequest).getRequest()).setRequest(request);
277                 portlet.render(renderRequest, renderResponse);
278             }
279 
280             // if we get this far we are home free
281             return;
282         }
283         catch (Throwable t)
284         {
285             if ( t instanceof UnavailableException )
286             {
287                 // destroy the portlet in the finally clause
288                 destroyPortlet = true;
289             }
290             
291             if (method != ContainerConstants.METHOD_ACTION)
292             {
293                 ServletContext context = getServletContext();
294                 context.log(JCS + "Error rendering portlet \"" + portletName + "\": " + t.toString(), t);
295                 try
296                 {
297                     String errorTemplate = getInitParameter("portal.error.page");
298                     if (errorTemplate == null)
299                     {
300                         errorTemplate = "/WEB-INF/templates/generic/html/error.vm";
301                     }
302                     if (null != context.getResource(errorTemplate))
303                     {
304                         RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(errorTemplate);
305                         request.setAttribute("e", t);
306                         StringWriter stackTrace = new StringWriter();
307                         t.printStackTrace(new PrintWriter(stackTrace));
308                         request.setAttribute("stacktrace", stackTrace.toString());
309                         dispatcher.include(request, response);
310                     }
311                     else
312                     {
313                         displayPortletNotAvailableMessage(t, response, portletName);
314                     }
315                 }
316                 catch (Throwable e)
317                 {
318                     displayPortletNotAvailableMessage(t, response, portletName);
319                 }
320                 finally
321                 {
322                     t.printStackTrace();
323                 }
324             }
325             else
326             {
327                 if ( t instanceof RuntimeException )
328                 {
329                     throw (RuntimeException)t;
330                 }
331                 else if (t instanceof IOException )
332                 {
333                     throw (IOException)t;
334                 }
335                 else if (t instanceof ServletException)
336                 {
337                     throw (ServletException)t;
338                 }
339                 else
340                 {
341                     throw new ServletException(t);
342                 }
343             }
344         }
345         finally
346         {
347             if ( destroyPortlet )
348             {
349                 // portlet throwed UnavailableException: take it out of service
350                 try
351                 {
352                     portlet.destroy();
353                 }
354                 catch (Exception e)
355                 {
356                     // never mind, it won't be used anymore.                 
357                 }
358             }
359             if (psm != null)
360             {
361                 RequestContext rc = (RequestContext)request.getAttribute(RequestContext.REQUEST_PORTALENV);
362                 psm.checkMonitorSession(contextName,rc.getRequest().getSession(),request.getSession(false));
363             }
364         }
365     }
366 
367     private void displayPortletNotAvailableMessage(Throwable t, HttpServletResponse response, String portletName)
368     throws IOException
369     {
370         getServletContext().log(JCS + "Error rendering JetspeedContainerServlet error page: " + t.toString(), t);
371         PrintWriter directError;
372         try
373         {
374             directError = new PrintWriter(response.getWriter());
375         }
376         catch (IllegalStateException e)
377         {
378             // Happens if get writer is already been called.
379             directError = new PrintWriter(new OutputStreamWriter(response.getOutputStream()));            
380         }
381         directError.write("Portlet is Not Available: " + portletName + "<br/>Reason: " + t.getMessage());
382         //t.printStackTrace(directError); 
383         directError.close();        
384     }
385     
386     /***
387      * In this application doGet and doPost are the same thing.
388      *
389      * @param req Servlet request.
390      * @param res Servlet response.
391      * @exception IOException a servlet exception.
392      * @exception ServletException a servlet exception.
393      */
394     public final void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException
395     {
396         doGet(req, res);
397     }
398 
399     // -------------------------------------------------------------------
400     // S E R V L E T  S H U T D O W N
401     // -------------------------------------------------------------------
402 
403     public final void destroy()
404     {
405       if ( contextName != null )
406       {
407         synchronized (contextName)
408         {
409           if ( startTimer != null )
410           {
411             startTimer.cancel();
412             startTimer = null;
413     }
414           else if ( started )
415           {
416             started = false;
417             PortletServices services = JetspeedPortletServices.getSingleton();
418             if (services != null)
419             {
420                 PortletApplicationManagement pam =
421                     (PortletApplicationManagement)services.getService("PAM");
422 
423                 if (pam != null)
424     {
425                     getServletContext().log(STOP_MSG + contextName);
426         try
427         {
428                       pam.stopPortletApplication(contextName);
429                     }
430                     catch (Exception e)
431             {
432                       getServletContext().log(STOP_FAILED_MSG + contextName, e);
433                     }
434                 }
435             }
436             contextName = null;
437             psm = null;
438             }
439         }
440         }
441     }
442 }