001package org.javasimon.spring.webmvc; 002 003import javax.servlet.http.HttpServletRequest; 004import javax.servlet.http.HttpServletResponse; 005 006import org.javasimon.Manager; 007import org.javasimon.SimonManager; 008import org.javasimon.Split; 009import org.javasimon.source.StopwatchSource; 010 011import org.springframework.web.servlet.HandlerInterceptor; 012import org.springframework.web.servlet.ModelAndView; 013 014/** 015 * Spring MVC interceptor monitors time spent in handlers (usually controllers) 016 * and views. Spring configuration: 017 * <pre>{@code 018 * <mvc:interceptors> 019 * <bean class="org.javasimon.spring.webmvc.MonitoringHandlerInterceptor"/> 020 * </mvc:interceptors> 021 * }</pre> 022 * 023 * @author gquintana 024 * @since Spring 3.1 025 */ 026public class MonitoringHandlerInterceptor implements HandlerInterceptor { 027 /** 028 * Current thread running split, if any. 029 */ 030 private final ThreadLocal<HandlerLocation> threadLocation = new ThreadLocal<>(); 031 032 /** 033 * Stopwatch source. 034 */ 035 private StopwatchSource<HandlerLocation> stopwatchSource; 036 037 /** 038 * Constructor with stopwatch source. 039 * 040 * @param stopwatchSource Stopwatch source 041 */ 042 public MonitoringHandlerInterceptor(StopwatchSource<HandlerLocation> stopwatchSource) { 043 this.stopwatchSource = stopwatchSource; 044 } 045 046 /** 047 * Constructor with simon manager and default stopwatch source. 048 * 049 * @param manager Manager manager 050 */ 051 public MonitoringHandlerInterceptor(Manager manager) { 052 stopwatchSource = new HandlerStopwatchSource(manager); 053 } 054 055 /** 056 * Default constructor: default stopwatch source, default manager. 057 */ 058 public MonitoringHandlerInterceptor() { 059 stopwatchSource = new HandlerStopwatchSource(SimonManager.manager()); 060 } 061 062 /** 063 * Start stopwatch for given name and thread. 064 * 065 * @return Running split 066 */ 067 protected final Split startStopwatch(HandlerLocation location) { 068 Split split = stopwatchSource.start(location); 069 location.setSplit(split); 070 return split; 071 } 072 073 /** 074 * Stop current thread stopwatch (if any). 075 * 076 * @return Stopped split 077 */ 078 protected final Split stopStopwatch() { 079 HandlerLocation location = threadLocation.get(); 080 Split split = null; 081 if (location != null) { 082 split = location.getSplit(); 083 split.stop(); 084 location.setSplit(null); 085 } 086 return split; 087 } 088 089 /** 090 * Invoked before controller. 091 */ 092 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 093 final HandlerLocation location = new HandlerLocation(request, handler, HandlerStep.CONTROLLER); 094 threadLocation.set(location); 095 096 // Start controller stopwatch 097 startStopwatch(location); 098 return true; 099 } 100 101 /** 102 * Invoked between controller and view. 103 */ 104 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { 105 // Stop controller stopwatch 106 stopStopwatch(); 107 108 HandlerLocation location = threadLocation.get(); 109 location.setStep(HandlerStep.VIEW); 110 111 // Start view stopwatch 112 startStopwatch(location); 113 } 114 115 /** 116 * Invoked after view. 117 */ 118 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { 119 // Stop view stopwatch 120 stopStopwatch(); 121 122 // Remove location 123 threadLocation.remove(); 124 } 125}