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.pluto.container.driver;
18  
19  import java.io.IOException;
20  import java.util.Timer;
21  import java.util.TimerTask;
22  
23  import javax.portlet.ActionRequest;
24  import javax.portlet.ActionResponse;
25  import javax.portlet.EventPortlet;
26  import javax.portlet.EventRequest;
27  import javax.portlet.EventResponse;
28  import javax.portlet.Portlet;
29  import javax.portlet.PortletConfig;
30  import javax.portlet.PortletException;
31  import javax.portlet.PortletRequest;
32  import javax.portlet.PortletResponse;
33  import javax.portlet.RenderRequest;
34  import javax.portlet.RenderResponse;
35  import javax.portlet.ResourceRequest;
36  import javax.portlet.ResourceResponse;
37  import javax.portlet.ResourceServingPortlet;
38  import javax.portlet.UnavailableException;
39  import javax.servlet.ServletConfig;
40  import javax.servlet.ServletContext;
41  import javax.servlet.ServletException;
42  import javax.servlet.http.HttpServlet;
43  import javax.servlet.http.HttpServletRequest;
44  import javax.servlet.http.HttpServletResponse;
45  
46  import org.apache.pluto.container.FilterManager;
47  import org.apache.pluto.container.PortletContainerException;
48  import org.apache.pluto.container.PortletInvokerService;
49  import org.apache.pluto.container.PortletRequestContext;
50  import org.apache.pluto.container.PortletResponseContext;
51  import org.apache.pluto.container.PortletWindow;
52  import org.apache.pluto.container.om.portlet.PortletDefinition;
53  
54  /**
55   * Portlet Invocation Servlet. This servlet recieves cross context requests from
56   * the the container and services the portlet request for the specified method.
57   *
58   * @version 1.1
59   * @since 09/22/2004
60   */
61  public class PortletServlet extends HttpServlet
62  {
63      private static final long serialVersionUID = -5096339022539360365L;
64  
65      static class NullPortlet implements EventPortlet, ResourceServingPortlet, Portlet
66      {
67          public void processEvent(EventRequest arg0, EventResponse arg1)
68          throws PortletException, IOException
69          {
70          }
71  
72          public void serveResource(ResourceRequest arg0, ResourceResponse arg1)
73          throws PortletException, IOException
74          {
75          }
76  
77          public void destroy()
78          {
79          }
80  
81          public void init(PortletConfig arg0) throws PortletException
82          {
83          }
84  
85          public void processAction(ActionRequest arg0, ActionResponse arg1)
86          throws PortletException, IOException
87          {
88          }
89  
90          public void render(RenderRequest arg0, RenderResponse arg1)
91          throws PortletException, IOException
92          {
93          }
94      }
95  
96      // Private Member Variables ------------------------------------------------
97      /**
98       * The portlet name as defined in the portlet app descriptor.
99       */
100     private String portletName;
101 
102     /**
103      * The portlet instance wrapped by this servlet.
104      */
105     private Portlet portlet;
106 
107     /**
108      * The internal portlet context instance.
109      */
110     private DriverPortletContext portletContext;
111 
112     /**
113      * The internal portlet config instance.
114      */
115     private DriverPortletConfig portletConfig;
116 
117     /**
118      * The Event Portlet instance (the same object as portlet) wrapped by this
119      * servlet.
120      */
121     private EventPortlet eventPortlet;
122 
123     /** The resource serving portlet instance wrapped by this servlet. */
124     private ResourceServingPortlet resourceServingPortlet;
125 
126     private PortletContextService contextService;
127 
128     private boolean started = false;
129     Timer   startTimer;
130 
131     // HttpServlet Impl --------------------------------------------------------
132 
133     public String getServletInfo()
134     {
135         return "Pluto PortletServlet [" + portletName + "]";
136     }
137 
138     /**
139      * Initialize the portlet invocation servlet.
140      *
141      * @throws ServletException
142      *             if an error occurs while loading portlet.
143      */
144     public void init(ServletConfig config) throws ServletException
145     {
146 
147         // Call the super initialization method.
148         super.init(config);
149 
150         // Retrieve portlet name as defined as an initialization parameter.
151         portletName = getInitParameter("portlet-name");
152 
153         started = false;
154 
155         startTimer = new Timer(true);
156         final ServletContext servletContext = getServletContext();
157         final ClassLoader paClassLoader = Thread.currentThread().getContextClassLoader();
158         startTimer.schedule(new TimerTask()
159         {
160             public void run()
161             {
162                 synchronized(servletContext)
163                 {
164                     if (startTimer != null)
165                     {
166                         if (attemptRegistration(servletContext, paClassLoader ))
167                         {
168                             startTimer.cancel();
169                             startTimer = null;
170                         }
171                     }
172                 }
173             }
174         }, 1, 1);
175     }
176 
177     protected boolean attemptRegistration(ServletContext context, ClassLoader paClassLoader)
178     {
179         if (PlutoServices.getServices() != null)
180         {
181             contextService = PlutoServices.getServices().getPortletContextService();
182             try
183             {
184                 ServletConfig sConfig = getServletConfig();
185                 if (sConfig == null)
186                 {
187                     String msg = "Problem obtaining servlet configuration(getServletConfig() returns null).";
188                     context.log(msg);
189                     return true;
190                 }
191 
192                 String applicationName = contextService.register(sConfig);
193                 started = true;
194                 portletContext = contextService.getPortletContext(applicationName);
195                 portletConfig = contextService.getPortletConfig(applicationName, portletName);
196 
197             }
198             catch (PortletContainerException ex)
199             {
200                 context.log(ex.getMessage(),ex);
201                 return true;
202             }
203 
204             PortletDefinition portletDD = portletConfig.getPortletDefinition();
205 
206             //          Create and initialize the portlet wrapped in the servlet.
207             try
208             {
209                 Class<?> clazz = paClassLoader.loadClass((portletDD.getPortletClass()));
210                 portlet = (Portlet) clazz.newInstance();
211                 portlet.init(portletConfig);
212                 initializeEventPortlet();
213                 initializeResourceServingPortlet();
214                 return true;
215             }
216             catch (Exception ex)
217             {
218                 context.log(ex.getMessage(),ex);
219                 // take out of service
220                 portlet = null;
221                 portletConfig = null;
222                 return true;
223             }
224         }
225         return false;
226     }
227 
228     public void destroy()
229     {
230         synchronized(getServletContext())
231         {
232             if ( startTimer != null )
233             {
234                 startTimer.cancel();
235                 startTimer = null;
236             }
237             else if ( started && portletContext != null)
238             {
239                 started = false;
240                 contextService.unregister(portletContext);
241                 if (portlet != null)
242                 {
243                     try
244                     {
245                         portlet.destroy();
246                     }
247                     catch (Exception e)
248                     {
249                         // ignore
250                     }
251                     portlet = null;
252                 }
253             }
254             super.destroy();
255         }
256     }
257 
258     protected void doGet(HttpServletRequest request,
259             HttpServletResponse response) throws ServletException, IOException
260             {
261         dispatch(request, response);
262             }
263 
264     protected void doPost(HttpServletRequest request,
265             HttpServletResponse response) throws ServletException, IOException
266             {
267         dispatch(request, response);
268             }
269 
270     protected void doPut(HttpServletRequest request,
271             HttpServletResponse response) throws ServletException, IOException
272             {
273         dispatch(request, response);
274             }
275 
276     // Private Methods ---------------------------------------------------------
277 
278     /**
279      * Dispatch the request to the appropriate portlet methods. This method
280      * assumes that the following attributes are set in the servlet request
281      * scope:
282      * <ul>
283      * <li>METHOD_ID: indicating which method to dispatch.</li>
284      * <li>PORTLET_REQUEST: the internal portlet request.</li>
285      * <li>PORTLET_RESPONSE: the internal portlet response.</li>
286      * </ul>
287      *
288      * @param request
289      *            the servlet request.
290      * @param response
291      *            the servlet response.
292      * @throws ServletException
293      * @throws IOException
294      */
295     private void dispatch(HttpServletRequest request,
296             HttpServletResponse response) throws ServletException, IOException
297             {
298         if (portlet == null)
299         {
300             throw new javax.servlet.UnavailableException("Portlet "+portletName+" unavailable");
301         }
302 
303         // Retrieve attributes from the servlet request.
304         Integer methodId = (Integer) request.getAttribute(PortletInvokerService.METHOD_ID);
305 
306         final PortletRequest portletRequest = (PortletRequest)request.getAttribute(PortletInvokerService.PORTLET_REQUEST);
307 
308         final PortletResponse portletResponse = (PortletResponse)request.getAttribute(PortletInvokerService.PORTLET_RESPONSE);
309 
310         final PortletRequestContext requestContext = (PortletRequestContext)portletRequest.getAttribute(PortletInvokerService.REQUEST_CONTEXT);
311         final PortletResponseContext responseContext = (PortletResponseContext)portletRequest.getAttribute(PortletInvokerService.RESPONSE_CONTEXT);
312 
313         final FilterManager filterManager = (FilterManager)request.getAttribute(PortletInvokerService.FILTER_MANAGER);
314 
315         request.removeAttribute(PortletInvokerService.METHOD_ID);
316         request.removeAttribute(PortletInvokerService.PORTLET_REQUEST);
317         request.removeAttribute(PortletInvokerService.PORTLET_RESPONSE);
318         request.removeAttribute(PortletInvokerService.FILTER_MANAGER);
319 
320         requestContext.init(portletConfig, getServletContext(), request, response);
321         responseContext.init(request, response);
322 
323         PortletWindow window = requestContext.getPortletWindow();
324 
325         PortletInvocationEvent event = new PortletInvocationEvent(portletRequest, window, methodId.intValue());
326 
327         notify(event, true, null);
328 
329         // FilterManager filtermanager = (FilterManager) request.getAttribute(
330         // "filter-manager");
331 
332         try
333         {
334 
335             // The requested method is RENDER: call Portlet.render(..)
336             if (methodId == PortletInvokerService.METHOD_RENDER)
337             {
338                 RenderRequest renderRequest = (RenderRequest) portletRequest;
339                 RenderResponse renderResponse = (RenderResponse) portletResponse;
340                 filterManager.processFilter(renderRequest, renderResponse,
341                         portlet, portletContext);
342             }
343 
344             // The requested method is RESOURCE: call
345             // ResourceServingPortlet.serveResource(..)
346             else if (methodId == PortletInvokerService.METHOD_RESOURCE)
347             {
348                 ResourceRequest resourceRequest = (ResourceRequest) portletRequest;
349                 ResourceResponse resourceResponse = (ResourceResponse) portletResponse;
350                 filterManager.processFilter(resourceRequest, resourceResponse,
351                         resourceServingPortlet, portletContext);
352             }
353 
354             // The requested method is ACTION: call Portlet.processAction(..)
355             else if (methodId == PortletInvokerService.METHOD_ACTION)
356             {
357                 ActionRequest actionRequest = (ActionRequest) portletRequest;
358                 ActionResponse actionResponse = (ActionResponse) portletResponse;
359                 filterManager.processFilter(actionRequest, actionResponse,
360                         portlet, portletContext);
361             }
362 
363             // The request methode is Event: call Portlet.processEvent(..)
364             else if (methodId == PortletInvokerService.METHOD_EVENT)
365             {
366                 EventRequest eventRequest = (EventRequest) portletRequest;
367                 EventResponse eventResponse = (EventResponse) portletResponse;
368                 filterManager.processFilter(eventRequest, eventResponse,
369                         eventPortlet, portletContext);
370             }
371             // The requested method is ADMIN: call handlers.
372             else if (methodId == PortletInvokerService.METHOD_ADMIN)
373             {
374                 PortalAdministrationService pas = PlutoServices.getServices().getPortalAdministrationService();
375 
376                 for (AdministrativeRequestListener l : pas.getAdministrativeRequestListeners())
377                 {
378                     l.administer(portletRequest, portletResponse);
379                 }
380             }
381 
382             // The requested method is LOAD: do nothing.
383             else if (methodId == PortletInvokerService.METHOD_LOAD)
384             {
385                 // Do nothing.
386             }
387 
388             notify(event, false, null);
389 
390         }
391         catch (UnavailableException ex)
392         {
393             //
394             // if (e.isPermanent()) { throw new
395             // UnavailableException(e.getMessage()); } else { throw new
396             // UnavailableException(e.getMessage(), e.getUnavailableSeconds());
397             // }
398             //
399 
400             // Portlet.destroy() isn't called by Tomcat, so we have to fix it.
401             try
402             {
403                 portlet.destroy();
404             }
405             catch (Throwable th)
406             {
407                 // Don't care for Exception
408                 this.getServletContext().log("Error during portlet destroy.", th);
409             }
410             // take portlet out of service
411             portlet = null;
412 
413             // TODO: Handle everything as permanently for now.
414             throw new javax.servlet.UnavailableException(ex.getMessage());
415 
416         }
417         catch (PortletException ex)
418         {
419             notify(event, false, ex);
420             throw new ServletException(ex);
421 
422         }
423             }
424 
425     protected void notify(PortletInvocationEvent event, boolean pre, Throwable e)
426     {
427         PortalAdministrationService pas = PlutoServices.getServices().getPortalAdministrationService();
428 
429         for (PortletInvocationListener listener : pas.getPortletInvocationListeners())
430         {
431             if (pre)
432             {
433                 listener.onBegin(event);
434             }
435             else if (e == null)
436             {
437                 listener.onEnd(event);
438             }
439             else
440             {
441                 listener.onError(event, e);
442             }
443         }
444     }
445 
446     private void initializeEventPortlet()
447     {
448         if (portlet instanceof EventPortlet)
449         {
450             eventPortlet = (EventPortlet) portlet;
451         }
452         else
453         {
454             eventPortlet = new NullPortlet();
455         }
456     }
457 
458     private void initializeResourceServingPortlet()
459     {
460         if (portlet instanceof ResourceServingPortlet)
461         {
462             resourceServingPortlet = (ResourceServingPortlet) portlet;
463         }
464         else
465         {
466             resourceServingPortlet = new NullPortlet();
467         }
468     }
469 }