View Javadoc

1   /**
2    * Copyright (C) 2005-2009 Alfresco Software Limited.
3    *
4    * This file is part of the Spring Surf Extension project.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.springframework.extensions.surf.site;
20  
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  
27  import javax.servlet.ServletRequest;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.springframework.extensions.surf.FrameworkUtil;
32  import org.springframework.extensions.surf.RequestContext;
33  import org.springframework.extensions.surf.render.RenderContext;
34  
35  /**
36   * A class that provides facilities for keeping track of the
37   * rendering times of components, regions, templates and pages.
38   * 
39   * The framework will call into this class when execution of said
40   * pieces.  If it is not enabled, then these calls will just NOP.
41   * Otherwise, they will log using the Framework logger.
42   * 
43   * @author muzquiano
44   */
45  public class Timer
46  {
47      protected static String TIMER_KEY = "timer";
48      protected static Log logger = LogFactory.getLog(Timer.class);
49      
50      /**
51       * Either print out to the configured Timer logger
52       * Or if they haven't set that up, just dump out to console
53       */
54      protected static void print(String value)
55      {
56          if (logger.isDebugEnabled())
57          {
58              logger.debug(value);
59          }
60      }
61      
62      /**
63       * Determines whether the timer is enabled.
64       * This is controlled via the configuration file and is false by default.
65       * 
66       * @return Whether the timer functionality is enabled or not
67       */
68      public static boolean isTimerEnabled()
69      {
70          return FrameworkUtil.getWebFrameworkConfiguration().isTimerEnabled();
71      }
72      
73      /**
74       * @return Whether to report in milliseconds (rather than nanoseconds)
75       */
76      protected static boolean showMilliseconds()
77      {
78          return true;
79      }
80      
81      /**
82       * Binds a timer container to the current context
83       * This must be called at the top of the request execution chain
84       * 
85       * @param context The current request context
86       */
87      public static void bindTimer(ServletRequest request)
88      {
89          bindTimer(request, false);
90      }
91      
92      public static void bindTimer(ServletRequest request, boolean forceNew)
93      {
94          Timer t = (Timer) request.getAttribute(TIMER_KEY);
95          if (t == null || forceNew)
96          {
97              t = new Timer();
98              request.setAttribute(TIMER_KEY, t);
99          }
100     }
101     
102     /**
103      * Releases the timer.  This should be called at the end of the
104      * request processing chain
105      * 
106      * @param context The current request context
107      */
108     public static void unbindTimer(ServletRequest request)
109     {
110         request.removeAttribute(TIMER_KEY);
111     }
112     
113     public static void start(RenderContext context, String blockId)
114     {
115         start(context.getRequest(), blockId);
116     }
117     
118     /**
119      * Begins timing for a specific block.  If timing has been captured
120      * previously for this block id, it will be added upon
121      * 
122      * @param context The current request context
123      * @param blockId The unique id of the block
124      */
125     public static void start(ServletRequest request, String blockId)
126     {
127         if (blockId == null)
128         {
129             return;
130         }
131         
132         Timer t = (Timer) request.getAttribute(TIMER_KEY);
133         if (t != null)
134         {
135             // check if this timer has not already been started
136             if (t.startTimes.get(blockId) == null)
137             {
138                 t.keys.add(blockId);
139             }
140             
141             Long l = new Long(System.nanoTime());
142             t.startTimes.put(blockId, l);
143         }
144     }
145     
146     public static void stop(RenderContext context, String blockId)
147     {
148         stop(context.getRequest(), blockId);
149     }
150     
151     public static void stop(ServletRequest request, String blockId)
152     {
153         long endTime = System.nanoTime();
154 
155         Timer t = (Timer) request.getAttribute(TIMER_KEY);
156         if (t != null)
157         {
158             // start time
159             Long startTime = (Long) t.startTimes.get(blockId);
160             if (startTime != null)
161             {
162                 // execution time
163                 long executionTime = endTime - startTime.longValue();
164                 
165                 // add to total time
166                 Long totalTime = (Long) t.totalTimes.get(blockId);
167                 if (totalTime == null)
168                 {
169                     totalTime = new Long(executionTime);
170                 }
171                 else
172                 {
173                     totalTime = new Long(totalTime.longValue() + executionTime);
174                 }
175                 
176                 // store back
177                 t.totalTimes.put(blockId, totalTime);
178             }
179         }
180     }
181     
182     /**
183      * Writes to debug out the report for a single block id
184      * 
185      * @param context The current request context
186      * @param blockId The block id to report on
187      */
188     public static void report(ServletRequest request, String blockId)
189     {
190         Timer t = (Timer) request.getAttribute(TIMER_KEY);
191         if (t != null)
192         {
193             Long l = (Long) t.totalTimes.get(blockId);
194             if (l != null)
195             {
196                 long value = (long) l.longValue();
197                 String label = "ns";
198                 
199                 if (Timer.showMilliseconds())
200                 {
201                     value = (long)(value / 1000000);
202                     label = "ms";
203                 }
204 
205                 RequestContext context = FrameworkUtil.getCurrentRequestContext();
206                 if (context == null)
207                 {
208                     print("[" + blockId + "] took " + value + " " + label);
209                 }
210                 else
211                 {
212                     print("[" + context.getId() + ":" + blockId + "] took " + value + " " + label);
213                 }
214             }
215         }
216     }
217     
218     public static void reportAll(ServletRequest request)
219     {
220         Timer t = (Timer) request.getAttribute(TIMER_KEY);
221         if (t != null)
222         {
223             // report timing blocks in order they were received
224             Iterator it = t.keys.iterator();
225             while (it.hasNext())
226             {
227                 String blockId = (String) it.next();
228                 report(request, blockId);
229             }
230         }
231     }
232     
233     public Timer()
234     {
235         this.totalTimes = new HashMap<String, Long>();
236         this.startTimes = new HashMap<String, Long>();
237         this.keys = new ArrayList<String>();
238     }
239     
240     protected Map<String, Long> totalTimes;
241     protected Map<String, Long> startTimes;
242     protected List<String> keys;
243 }