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.Worker;
49  import org.apache.jetspeed.aggregator.CurrentWorkerContext;
50  
51  /***
52   * Jetspeed Container entry point.
53   *
54   * @author <a href="mailto:david@bluesunrise.com">David Sean Taylor</a>
55   * @version $Id: JetspeedContainerServlet.java 554827 2007-07-10 05:12:23Z taylor $
56   */
57  public class JetspeedContainerServlet extends HttpServlet 
58  {
59      private String  contextName;
60      private boolean started = false;
61      private Timer   startTimer = null;
62      private PortalSessionsManager psm;
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  
88              if (null == contextName || contextName.length() == 0)
89              {
90                  contextName = null; // just to make sure for the destroy method
91                  
92                  throw new ServletException(JCS + "Portlet Application contextName not supplied in Init Parameters.");
93              }            
94              String paDir = context.getRealPath("/");
95              if ( paDir == null )
96                  {
97                throw new ServletException(JCS + " Initialization of PortletApplication at "+contextName+" without access to its real path not supported");
98                  }
99  
100             context.log(INIT_START_MSG + contextName);            
101             System.out.println(INIT_START_MSG + contextName);            
102 
103             try
104             {                
105               startPortletApplication(context, paDir, Thread.currentThread().getContextClassLoader());
106             }
107             catch (Exception e)
108             {
109                 String message = INIT_FAILED_MSG + contextName;
110                 context.log(message, e);
111                 System.err.println(message);
112                 throw new ServletException(message, e);
113             }
114 
115             context.log(INIT_DONE_MSG + contextName);
116             System.out.println(INIT_DONE_MSG + contextName);
117         }
118     }
119 
120     private void startPortletApplication(final ServletContext context, final String paDir, final ClassLoader paClassLoader)
121     throws ServletException
122     {
123 
124 /* TODO: Ate Douma, 2005-03-25
125    Under fusion, this call always results in a javax.naming.NameNotFoundException: "Name jdbc is not bound in this Context"
126    but when started from a separate (timer) Thread, even with only a delay of 1ms, it works again.
127    I don't have any clue what is the cause of this or how to solve it, thus for now I disabled starting directly
128 
129         if (attemptStart(context, contextName, paDir, paClassLoader)) 
130         {
131           started = true;
132             return;
133         }
134 */
135         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.";
136         context.log(START_DELAYED_MSG);
137         startTimer = new Timer(true);
138         startTimer.schedule(
139                 new TimerTask() {
140                     public void run() {
141                       synchronized(contextName)
142                       {
143                         if (startTimer != null)
144                         {
145                           if (attemptStart(context, contextName, paDir, paClassLoader)) {
146                             startTimer.cancel();
147                             startTimer = null;
148                         } else {
149                             context.log(START_DELAYED_MSG);
150                           }
151                         }
152                         }
153                     }
154                 },
155 //                10000, Setting delay to 1ms, see TODO comment above
156                 1,
157                 10000);
158     }
159 
160     private boolean attemptStart(ServletContext context, String contextPath, String paDir, ClassLoader paClassLoader) 
161     {
162         try
163         {
164             context.log(TRY_START_MSG + contextPath);
165             PortletServices services = JetspeedPortletServices.getSingleton();
166             if (services != null)
167             {
168                 PortletApplicationManagement pam =
169                     (PortletApplicationManagement)services.getService("PAM");
170 
171                 if (pam != null && pam.isStarted())
172                 {
173                     DirectoryHelper paDirHelper = new DirectoryHelper(new File(paDir));
174                     pam.startPortletApplication(contextPath, paDirHelper, paClassLoader);
175                     started = true;
176                     psm = (PortalSessionsManager)services.getService(PortalSessionsManager.SERVICE_NAME);
177 
178                     context.log(STARTED_MSG + contextPath);
179                     return true;
180                 }
181             }
182         }
183         catch (Exception e)
184         {
185             context.log(INIT_FAILED_MSG + contextPath, e);
186             return true; // don't try again
187         }
188         return false;
189     }    
190     
191     // -------------------------------------------------------------------
192     // R E Q U E S T  P R O C E S S I N G
193     // -------------------------------------------------------------------
194 
195     /***
196      * The primary method invoked when the Jetspeed servlet is executed.
197      *
198      * @param request Servlet request.
199      * @param ressponse Servlet response.
200      * @exception IOException a servlet exception.
201      * @exception ServletException a servlet exception.
202      */
203     public final void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
204     {
205         String portletName = null;
206         Integer method = ContainerConstants.METHOD_NOOP;
207         Portlet portlet = null;
208         boolean destroyPortlet = false;
209         boolean isParallelMode = false;
210         
211         try
212         {
213             isParallelMode = (Thread.currentThread() instanceof Worker || CurrentWorkerContext.getCurrentWorkerContextUsed());
214 
215             if (isParallelMode)
216             {
217                 method = (Integer) CurrentWorkerContext.getAttribute(ContainerConstants.METHOD_ID);
218             }
219             else
220             {
221                 method = (Integer) request.getAttribute(ContainerConstants.METHOD_ID);
222             }
223             if (method == ContainerConstants.METHOD_NOOP)
224             {
225                 return;
226             }
227             if (isParallelMode)
228             {
229                 portlet = (Portlet) CurrentWorkerContext.getAttribute(ContainerConstants.PORTLET);
230                 portletName = (String) CurrentWorkerContext.getAttribute(ContainerConstants.PORTLET_NAME);
231             }
232             else
233             {
234                 portlet = (Portlet)request.getAttribute(ContainerConstants.PORTLET);
235                 portletName = (String)request.getAttribute(ContainerConstants.PORTLET_NAME);
236                 request.removeAttribute(ContainerConstants.PORTLET);
237             }
238 
239             if (method == ContainerConstants.METHOD_ACTION)
240             {
241                 ActionRequest actionRequest = (ActionRequest) request.getAttribute(ContainerConstants.PORTLET_REQUEST);
242                 ActionResponse actionResponse = (ActionResponse) request.getAttribute(ContainerConstants.PORTLET_RESPONSE);
243                 // inject the current request into the actionRequest handler (o.a.j.engine.servlet.ServletRequestImpl)
244                 ((HttpServletRequestWrapper)((HttpServletRequestWrapper)actionRequest).getRequest()).setRequest(request);
245 
246                 portlet.processAction(actionRequest, actionResponse);
247             }
248             else if (method == ContainerConstants.METHOD_RENDER)
249             {
250                 RenderRequest renderRequest = null;
251                 RenderResponse renderResponse =  null;
252 
253                 if (isParallelMode)
254                 {
255                     renderRequest = (RenderRequest) CurrentWorkerContext.getAttribute(ContainerConstants.PORTLET_REQUEST);
256                     renderResponse = (RenderResponse) CurrentWorkerContext.getAttribute(ContainerConstants.PORTLET_RESPONSE);
257                 }
258                 else
259                 {
260                     renderRequest = (RenderRequest) request.getAttribute(ContainerConstants.PORTLET_REQUEST);
261                     renderResponse = (RenderResponse) request.getAttribute(ContainerConstants.PORTLET_RESPONSE);
262                 }                
263                 // inject the current request into the renderRequest handler (o.a.j.engine.servlet.ServletRequestImpl)
264                 ((HttpServletRequestWrapper)((HttpServletRequestWrapper)renderRequest).getRequest()).setRequest(request);
265                 portlet.render(renderRequest, renderResponse);
266             }
267 
268             // if we get this far we are home free
269             return;
270         }
271         catch (Throwable t)
272         {
273             if ( t instanceof UnavailableException )
274             {
275                 // destroy the portlet in the finally clause
276                 destroyPortlet = true;
277             }
278             
279             if (method != ContainerConstants.METHOD_ACTION)
280             {
281                 ServletContext context = getServletContext();
282                 context.log(JCS + "Error rendering portlet \"" + portletName + "\": " + t.toString(), t);
283                 try
284                 {
285                     String errorTemplate = getInitParameter("portal.error.page");
286                     if (errorTemplate == null)
287                     {
288                         errorTemplate = "/WEB-INF/templates/generic/html/error.vm";
289                     }
290                     if (null != context.getResource(errorTemplate))
291                     {
292                         RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(errorTemplate);
293                         request.setAttribute("e", t);
294                         StringWriter stackTrace = new StringWriter();
295                         t.printStackTrace(new PrintWriter(stackTrace));
296                         request.setAttribute("stacktrace", stackTrace.toString());
297                         dispatcher.include(request, response);
298                     }
299                     else
300                     {
301                         displayPortletNotAvailableMessage(t, response, portletName);
302                     }
303                 }
304                 catch (Throwable e)
305                 {
306                     displayPortletNotAvailableMessage(t, response, portletName);
307                 }
308                 finally
309                 {
310                     t.printStackTrace();
311                 }
312             }
313             else
314             {
315                 if ( t instanceof RuntimeException )
316                 {
317                     throw (RuntimeException)t;
318                 }
319                 else if (t instanceof IOException )
320                 {
321                     throw (IOException)t;
322                 }
323                 else if (t instanceof ServletException)
324                 {
325                     throw (ServletException)t;
326                 }
327                 else
328                 {
329                     throw new ServletException(t);
330                 }
331             }
332         }
333         finally
334         {
335             if ( destroyPortlet )
336             {
337                 // portlet throwed UnavailableException: take it out of service
338                 try
339                 {
340                     portlet.destroy();
341                 }
342                 catch (Exception e)
343                 {
344                     // never mind, it won't be used anymore.                 
345                 }
346             }
347             if (psm != null)
348             {
349                 RequestContext rc = (RequestContext)request.getAttribute(RequestContext.REQUEST_PORTALENV);
350                 psm.checkMonitorSession(contextName,rc.getRequest().getSession(),request.getSession(false));
351             }
352         }
353     }
354 
355     private void displayPortletNotAvailableMessage(Throwable t, HttpServletResponse response, String portletName)
356     throws IOException
357     {
358         getServletContext().log(JCS + "Error rendering JetspeedContainerServlet error page: " + t.toString(), t);
359         PrintWriter directError;
360         try
361         {
362             directError = new PrintWriter(response.getWriter());
363         }
364         catch (IllegalStateException e)
365         {
366             // Happens if get writer is already been called.
367             directError = new PrintWriter(new OutputStreamWriter(response.getOutputStream()));            
368         }
369         directError.write("Portlet is Not Available: " + portletName + "<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, HttpServletResponse res) throws IOException, ServletException
383     {
384         doGet(req, res);
385     }
386 
387     // -------------------------------------------------------------------
388     // S E R V L E T  S H U T D O W N
389     // -------------------------------------------------------------------
390 
391     public final void destroy()
392     {
393       if ( contextName != null )
394       {
395         synchronized (contextName)
396         {
397           if ( startTimer != null )
398           {
399             startTimer.cancel();
400             startTimer = null;
401     }
402           else if ( started )
403           {
404             started = false;
405             PortletServices services = JetspeedPortletServices.getSingleton();
406             if (services != null)
407             {
408                 PortletApplicationManagement pam =
409                     (PortletApplicationManagement)services.getService("PAM");
410 
411                 if (pam != null)
412     {
413                     getServletContext().log(STOP_MSG + contextName);
414         try
415         {
416                       pam.stopPortletApplication(contextName);
417                     }
418                     catch (Exception e)
419             {
420                       getServletContext().log(STOP_FAILED_MSG + contextName, e);
421                     }
422                 }
423             }
424             contextName = null;
425             psm = null;
426             }
427         }
428         }
429     }
430 }