001 /* 002 * Copyright 2008-2009 the original author or authors. 003 * The contents of this file are subject to the Mozilla Public License 004 * Version 1.1 (the "License"); you may not use this file except in 005 * compliance with the License. You may obtain a copy of the License at 006 * http://www.mozilla.org/MPL/ 007 * 008 * Software distributed under the License is distributed on an "AS IS" 009 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 010 * License for the specific language governing rights and limitations 011 * under the License. 012 */ 013 014 package com.mtgi.analytics.servlet; 015 016 import java.util.Collection; 017 018 import javax.servlet.ServletContext; 019 import javax.servlet.ServletContextEvent; 020 import javax.servlet.ServletContextListener; 021 import javax.servlet.ServletRequest; 022 import javax.servlet.ServletRequestEvent; 023 import javax.servlet.ServletRequestListener; 024 import javax.servlet.http.HttpServletRequest; 025 026 import org.apache.commons.logging.Log; 027 import org.apache.commons.logging.LogFactory; 028 import org.springframework.web.context.WebApplicationContext; 029 import org.springframework.web.context.support.WebApplicationContextUtils; 030 031 import com.mtgi.analytics.BehaviorEvent; 032 033 /** 034 * Logs behavior tracking events for incoming servlet requests. This listener is activated by the 035 * <code>bt:http-requests</code> Spring XML tag. It is an alternative to {@link BehaviorTrackingFilter} 036 * registration in <code>web.xml</code>. BehaviorTrackingFilter is more flexible, but is slightly more 037 * complex to configure. At most one of these methods (bt:http-requests or BehaviorTrackingFilter) should 038 * be used in a given application, otherwise errors will be thrown during application startup. 039 */ 040 public class BehaviorTrackingListener implements ServletRequestListener, ServletContextListener { 041 042 private static final Log log = LogFactory.getLog(BehaviorTrackingListener.class); 043 044 private static final String ATT_EVENTS = BehaviorTrackingListener.class.getName() + ".events"; 045 046 private ServletRequestBehaviorTrackingAdapter[] adapters = null; 047 048 @SuppressWarnings("unchecked") 049 public void contextInitialized(ServletContextEvent event) { 050 ServletContext context = event.getServletContext(); 051 WebApplicationContext spring = WebApplicationContextUtils.getWebApplicationContext(context); 052 if (spring != null) { 053 Collection<ServletRequestBehaviorTrackingAdapter> beans = spring.getBeansOfType(ServletRequestBehaviorTrackingAdapter.class, false, false).values(); 054 if (!beans.isEmpty()) { 055 if (BehaviorTrackingFilter.isFiltered(context)) 056 throw new IllegalStateException("You have configured both BehaviorTrackingFilters and BehaviorTrackingListeners in the same web application. Only one of these methods may be used in a single application."); 057 adapters = beans.toArray(new ServletRequestBehaviorTrackingAdapter[beans.size()]); 058 log.info("BehaviorTracking for HTTP servlet requests started"); 059 } 060 } 061 } 062 063 public void contextDestroyed(ServletContextEvent event) { 064 if (adapters != null) { 065 log.info("BehaviorTracking for HTTP servlet requests stopped"); 066 adapters = null; 067 } 068 } 069 070 public void requestInitialized(ServletRequestEvent event) { 071 if (adapters != null) { 072 BehaviorEvent[] events = new BehaviorEvent[adapters.length]; 073 ServletRequest request = event.getServletRequest(); 074 request.setAttribute(ATT_EVENTS, events); 075 076 for (int i = 0; i < adapters.length; ++i) 077 try { 078 events[i] = adapters[i].start(request); 079 } catch (Exception e) { 080 log.error("Error starting http event", e); 081 } 082 } 083 } 084 085 public void requestDestroyed(ServletRequestEvent event) { 086 if (adapters != null) { 087 ServletRequest request = event.getServletRequest(); 088 BehaviorEvent[] events = (BehaviorEvent[])request.getAttribute(ATT_EVENTS); 089 if (events == null) { 090 log.error("no behavior events stored in the current request (" + ((HttpServletRequest)request).getRequestURI()); 091 } else { 092 request.removeAttribute(ATT_EVENTS); 093 for (int i = 0; i < adapters.length; ++i) 094 try { 095 adapters[i].stop(events[i]); 096 } catch (Exception e) { 097 log.error("Error stopping http event", e); 098 } 099 } 100 } 101 } 102 103 }