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.engine;
18  
19  import java.io.IOException;
20  import java.security.Principal;
21  
22  import javax.security.auth.Subject;
23  import javax.servlet.ServletConfig;
24  import javax.servlet.ServletContext;
25  import javax.servlet.ServletException;
26  import javax.servlet.http.HttpServlet;
27  import javax.servlet.http.HttpServletRequest;
28  import javax.servlet.http.HttpServletResponse;
29  import javax.servlet.http.HttpSessionEvent;
30  import javax.servlet.http.HttpSessionListener;
31  
32  import org.apache.commons.configuration.Configuration;
33  import org.apache.commons.configuration.PropertiesConfiguration;
34  import org.apache.commons.lang.exception.ExceptionUtils;
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.jetspeed.Jetspeed;
38  import org.apache.jetspeed.PortalReservedParameters;
39  import org.apache.jetspeed.cache.ContentCacheKeyGenerator;
40  import org.apache.jetspeed.cache.JetspeedCache;
41  import org.apache.jetspeed.components.ComponentManager;
42  import org.apache.jetspeed.components.SpringComponentManager;
43  import org.apache.jetspeed.components.factorybeans.ServletConfigFactoryBean;
44  import org.apache.jetspeed.container.session.PortalSessionsManager;
45  import org.apache.jetspeed.engine.servlet.ServletHelper;
46  import org.apache.jetspeed.exception.JetspeedException;
47  import org.apache.jetspeed.pipeline.valve.SecurityValve;
48  import org.apache.jetspeed.request.RequestContext;
49  import org.apache.jetspeed.request.RequestContextComponent;
50  import org.apache.jetspeed.security.SecurityHelper;
51  import org.apache.jetspeed.security.UserPrincipal;
52  import org.apache.jetspeed.services.JetspeedPortletServices;
53  import org.apache.jetspeed.services.PortletServices;
54  import org.apache.jetspeed.statistics.PortalStatistics;
55  
56  /***
57   * Jetspeed Servlet entry point.
58   * 
59   * @author <a href="mailto:david@bluesunrise.com">David Sean Taylor </a>
60   * @version $Id: JetspeedServlet.java 553340 2007-07-04 22:00:09Z taylor $
61   */
62  public class JetspeedServlet 
63  extends HttpServlet 
64  implements JetspeedEngineConstants, HttpSessionListener
65  {
66      private static Log log;
67      private static Log console;
68  
69      /***
70       * In certain situations the init() method is called more than once,
71       * somtimes even concurrently. This causes bad things to happen, so we use
72       * this flag to prevent it.
73       */
74      private static boolean firstInit = true;
75  
76      /***
77       * Whether init succeeded or not.
78       */
79      private static Throwable initFailure = null;
80  
81      /***
82       * Should initialization activities be performed during doGet() execution?
83       */
84      private static boolean firstDoGet = true;
85  
86      /***
87       * The Jetspeed Engine
88       */
89      private static Engine engine;
90      private static RequestContextComponent contextComponent;
91      
92      private static String webappRoot;
93  
94      // -------------------------------------------------------------------
95      // I N I T I A L I Z A T I O N
96      // -------------------------------------------------------------------
97      private static final String INIT_START_MSG = "Jetspeed Starting Initialization...";
98      private static final String INIT_DONE_MSG = "Jetspeed Initialization complete, Ready to service requests.";
99  
100     /***
101      * Intialize Servlet.
102      */
103     public final void init( ServletConfig config ) throws ServletException
104     {
105         synchronized (this.getClass())
106         {
107             if ( log == null )
108             {
109                 log = LogFactory.getLog(JetspeedServlet.class);
110                 console = LogFactory.getLog(CONSOLE_LOGGER);                
111             }
112             
113             console.info(INIT_START_MSG);
114 
115             super.init(config);
116 
117             if (!firstInit)
118             {
119                 log.info("Double initialization of Jetspeed was attempted!");
120                 console.info("Double initialization of Jetspeed was attempted!");
121                 return;
122             }
123             // executing init will trigger some static initializers, so we have
124             // only one chance.
125             firstInit = false;
126 
127             try
128             {
129 
130                 ServletContext context = config.getServletContext();
131 
132                 String propertiesFilename = ServletHelper.findInitParameter(context, config, JETSPEED_PROPERTIES_KEY,
133                         JETSPEED_PROPERTIES_DEFAULT);
134 
135                 String applicationRoot = ServletHelper.findInitParameter(context, config, APPLICATION_ROOT_KEY,
136                         APPLICATION_ROOT_DEFAULT);
137 
138                 console.info("JetspeedServlet identifying web application root...");
139                 webappRoot = config.getServletContext().getRealPath("/");
140                 console.info("JetspeedServlet identifed web application root as " + webappRoot);
141 
142                 if (applicationRoot == null || applicationRoot.equals(WEB_CONTEXT))
143                 {
144                     applicationRoot = webappRoot;
145                 }
146 
147                 Configuration properties = new PropertiesConfiguration(ServletHelper.getRealPath(
148                         config, propertiesFilename));
149 
150                 properties.setProperty(APPLICATION_ROOT_KEY, applicationRoot);
151                 properties.setProperty(WEBAPP_ROOT_KEY, webappRoot);
152 
153                 console.info("JetspeedServlet attempting to create the  portlet engine...");
154 
155                 engine = new JetspeedEngine(properties, applicationRoot, config, initializeComponentManager(config, applicationRoot, properties));
156              
157                 console.info("JetspeedServlet attempting to start the Jetspeed Portal Engine...");
158                 Jetspeed.setEngine(engine);
159                 engine.start();                
160                 console.info("JetspeedServlet has successfuly started the Jetspeed Portal Engine....");
161                 contextComponent = (RequestContextComponent) Jetspeed.getComponentManager().getComponent(RequestContextComponent.class);
162             }
163             catch (Throwable e)
164             {
165                 // save the exception to complain loudly later :-)
166                 final String msg = "Jetspeed: init() failed: ";
167                 initFailure = e;               
168                 log.fatal(msg, e);
169                 console.fatal(msg, e);
170             }
171 
172             console.info(INIT_DONE_MSG);
173             log.info(INIT_DONE_MSG);
174         }
175     }
176 
177     /***
178      * Initializes the services which need <code>RunData</code> to initialize
179      * themselves (post startup).
180      * 
181      * @param data
182      *            The first <code>GET</code> request.
183      */
184     public final void init( HttpServletRequest request, HttpServletResponse response )
185     {
186         synchronized (JetspeedServlet.class)
187         {
188             if (firstDoGet)
189             {
190                 // Mark that we're done.
191                 firstDoGet = false;
192             }
193         }
194     }
195 
196     // -------------------------------------------------------------------
197     // R E Q U E S T P R O C E S S I N G
198     // -------------------------------------------------------------------
199 
200     /***
201      * The primary method invoked when the Jetspeed servlet is executed.
202      * 
203      * @param req
204      *            Servlet request.
205      * @param res
206      *            Servlet response.
207      * @exception IOException
208      *                a servlet exception.
209      * @exception ServletException
210      *                a servlet exception.
211      */
212     public final void doGet( HttpServletRequest req, HttpServletResponse res ) throws IOException, ServletException
213     {
214         try
215         {
216             // Check to make sure that we started up properly.
217             if (initFailure != null)
218             {
219                 throw new ServletException("Failed to initalize jetspeed.  "+initFailure.toString(), initFailure);
220             }
221 
222             // If this is the first invocation, perform some late
223             // initialization.
224             if (firstDoGet)
225             {
226                 init(req, res);
227             }
228 
229             //If we already passed though the content filter DON'T send it to the
230             // engine.  This is a crappy hack until we find a better solution.
231             String wasFiltered = (String) req.getAttribute("org.apache.jetspeed.content.filtered");
232             if (wasFiltered == null || !wasFiltered.equals("true"))
233             {
234                 // ensure that no proxy or brower caching is performed
235                 // on dynamic responses resulting from pipeline execution
236                 res.setHeader("Cache-Control", "no-cache,no-store,private"); // HTTP/1.1 modern browser/proxy
237                 res.setHeader("Pragma", "no-cache");                         // HTTP/1.0 non-standard proxy 
238                 res.setHeader("Expires", "0");                               // HTTP/1.0 browser/proxy
239 
240                 // send request through pipeline
241                 RequestContext context = contextComponent.create(req, res, getServletConfig());
242                 engine.service(context);
243                 contextComponent.release(context);
244             }
245 
246         }
247         catch (JetspeedException e)
248         {
249             final String msg = "Fatal error encountered while processing portal request: "+e.toString();
250             log.fatal(msg, e);
251             throw new ServletException(msg, e);
252         }
253     }
254 
255     /***
256      * In this application doGet and doPost are the same thing.
257      * 
258      * @param req
259      *            Servlet request.
260      * @param res
261      *            Servlet response.
262      * @exception IOException
263      *                a servlet exception.
264      * @exception ServletException
265      *                a servlet exception.
266      */
267     public final void doPost( HttpServletRequest req, HttpServletResponse res ) throws IOException, ServletException
268     {
269         doGet(req, res);
270     }
271 
272     // -------------------------------------------------------------------
273     // S E R V L E T S H U T D O W N
274     // -------------------------------------------------------------------
275 
276     /***
277      * The <code>Servlet</code> destroy method. Invokes
278      * <code>ServiceBroker</code> tear down method.
279      */
280     public final void destroy()
281     {
282         try
283         {
284             Jetspeed.shutdown();
285         }
286         catch (JetspeedException e)
287         {
288             log.fatal("Jetspeed: shutdown() failed: ", e);
289             System.err.println(ExceptionUtils.getStackTrace(e));
290         }
291 
292         // Allow turbine to be started back up again.
293         firstInit = true;
294 
295         log.info("Done shutting down!");
296     }    
297     
298     /***
299      * If you prefer to use a component manager other than Spring, you
300      * can override this method to do so.  Do not explicitly call start()
301      * of the ComponentManager as the JetspeedEngine will do this within its
302      * own start() method.
303      * 
304      * @param servletConfig
305      * @param appRoot
306      * @param configuration
307      * @return
308      * @throws IOException
309      */
310     protected ComponentManager initializeComponentManager(ServletConfig servletConfig, String appRoot, Configuration configuration) throws IOException
311     {
312         ServletConfigFactoryBean.setServletConfig(servletConfig);
313         final String assemblyDir = configuration.getString("assembly.dir","/WEB-INF/assembly");
314         final String assemblyFileExtension = configuration.getString("assembly.extension",".xml");
315                     
316         String[] bootConfigs = new String[] {"/WEB-INF/assembly/boot/*.xml"};
317         String[] appConfigs =  new String[] {assemblyDir+"/*"+assemblyFileExtension, assemblyDir+"/override/*"+assemblyFileExtension};
318         ServletContext servletContext = servletConfig.getServletContext();
319         SpringComponentManager cm = new SpringComponentManager(bootConfigs, appConfigs, servletContext, appRoot);      
320         
321         return cm;        
322     }
323     
324     public void sessionCreated(HttpSessionEvent se)
325     {
326         PortletServices services = JetspeedPortletServices.getSingleton();
327         if (services != null)
328         {
329             PortalSessionsManager psm = (PortalSessionsManager)services.getService(PortalSessionsManager.SERVICE_NAME);
330             if (psm != null)
331             {
332                 psm.portalSessionCreated(se.getSession());
333             }
334         }
335     }
336     
337     public void sessionDestroyed(HttpSessionEvent se)
338     {
339         Subject subject = (Subject)se.getSession().getAttribute(PortalReservedParameters.SESSION_KEY_SUBJECT);
340         if (subject == null)
341             return;
342         if (firstInit)
343         {
344             // Servlet already destroyed, 
345             // Can't reliably access ComponentManager (Spring) anymore
346             // as for instance WAS 6.0.2 has a bug invoking this method with a wrong classLoader (not the one for the WebApp)
347             return;
348         }        
349         Principal subjectUserPrincipal = SecurityHelper.getPrincipal(subject, UserPrincipal.class);
350         PortalStatistics statistics = (PortalStatistics)engine.getComponentManager().getComponent("PortalStatistics");
351         long sessionLength = System.currentTimeMillis() - se.getSession().getCreationTime();
352         String ipAddress = (String)se.getSession().getAttribute(SecurityValve.IP_ADDRESS);
353         statistics.logUserLogout(ipAddress, subjectUserPrincipal.getName(), sessionLength);    
354         JetspeedCache portletContentCache = (JetspeedCache)engine.getComponentManager().getComponent("portletContentCache");
355         JetspeedCache decorationContentCache = null;
356         
357         try
358         {
359             decorationContentCache = (JetspeedCache)engine.getComponentManager().getComponent("decorationContentCache");
360         }
361         catch (Exception e)
362         {
363         }
364         
365         ContentCacheKeyGenerator generator = (ContentCacheKeyGenerator)engine.getComponentManager().getComponent("ContentCacheKeyGenerator");
366         
367         if (generator.isCacheBySessionId())
368         {
369             portletContentCache.evictContentForUser(se.getSession().getId());
370             
371             if (decorationContentCache != null)
372             {
373                 decorationContentCache.evictContentForUser(se.getSession().getId());
374             }
375         }
376         else
377         {
378             portletContentCache.evictContentForUser(subjectUserPrincipal.getName());
379             
380             if (decorationContentCache != null)
381             {
382                 decorationContentCache.evictContentForUser(subjectUserPrincipal.getName());            }
383         }
384     }
385 }