All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opensymphony.xwork2.util.profiling.UtilTimerStack Maven / Gradle / Ivy

Go to download

XWork is an command-pattern framework that is used to power WebWork as well as other applications. XWork provides an Inversion of Control container, a powerful expression language, data type conversion, validation, and pluggable configuration.

There is a newer version: 2.1.3
Show newest version
/*
 * Copyright (c) 2002-2003, Atlassian Software Systems Pty Ltd All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.
 *     * Neither the name of Atlassian Software Systems Pty Ltd nor the names of
 * its contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.opensymphony.xwork2.util.profiling;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * A timer stack.
 *
 * 

* * * * Struts2 profiling aspects involves the following :- *

    *
  • ActionContextCleanUp
  • *
  • FreemarkerPageFilter
  • *
  • DispatcherFilter
  • *
      *
    • Dispatcher
    • *
        *
      • creation of DefaultActionProxy
      • *
          *
        • creation of DefaultActionInvocation
        • *
            *
          • creation of Action
          • *
          *
        *
      • execution of DefaultActionProxy
      • *
          *
        • invocation of DefaultActionInvocation
        • *
            *
          • invocation of Interceptors
          • *
          • invocation of Action
          • *
          • invocation of PreResultListener
          • *
          • invocation of Result
          • *
          *
        *
      *
    *
* * * * * * * XWork2 profiling aspects involves the following :- *
    *
      *
    • creation of DefaultActionProxy
    • *
        *
      • creation of DefaultActionInvocation
      • *
          *
        • creation of Action
        • *
        *
      *
    • execution of DefaultActionProxy
    • *
        *
      • invocation of DefaultActionInvocation
      • *
          *
        • invocation of Interceptors
        • *
        • invocation of Action
        • *
        • invocation of PreResultListener
        • *
        • invocation of Result
        • *
        *
      *
    *
* * * * * * * Activating / Deactivating of the profiling feature could be done through:- * * * *

* * System properties:-

*

 * 
 * 
 *  -Dxwork.profile.activate=true
 *  
 *  
 * 
* * * * This could be done in the container startup script eg. CATALINA_OPTS in catalina.sh * (tomcat) or using "java -Dxwork.profile.activate=true -jar start.jar" (jetty) * * * *

* Code :-

*

 * 
 *   
 *  UtilTimerStack.setActivate(true);
 *  
 *  // or 
 *  
 *  System.setProperty("xwork.profile.activate", "true");
 *   
 *  // or
 *  
 *  System.setProperty(UtilTimerStack.ACTIVATE_PROPERTY, "true");
 *  
 *  
 * 
* * * * * * This could be done in a static block, in a Spring bean with lazy-init="false", * in a Servlet with init-on-startup as some numeric value, in a Filter or * Listener's init method etc. * * * *

* Parameter:- * *

 * 
 * 
 * <action ... >  
 *  ...
 *  <interceptor-ref name="profiling">
 *      <param name="profilingKey">profiling</param>
 *  </interceptor-ref>
 *  ...
 * </action>
 * 
 * or 
 * 
 * <action .... >
 * ...
 *  <interceptor-ref name="profiling" />
 * ...
 * </action>
 * 
 * through url
 * 
 * http://host:port/context/namespace/someAction.action?profiling=true
 * 
 * through code
 * 
 * ActionContext.getContext().getParameters().put("profiling", "true);
 * 
 * 
 * 
* * * * * To use profiling activation through parameter, one will need to pass in through * the 'profiling' parameter (which is the default) and could be changed through * the param tag in the interceptor-ref. * * * *

* Warning:

* * * Profiling activation through parameter will need the followings:- *

    *
  • Profiling interceptor
  • *
  • dev mode on (struts.devMode=true in struts.properties) *
* * * *

* * * * One could filter out the profile logging by having a System property as follows. With this * 'xwork.profile.mintime' property, one could only log profile information when its execution time * exceed those specified in 'xwork.profile.mintime' system property. If no such property is specified, * it will be assumed to be 0, hence all profile information will be logged. * * * *

 * 
 * 
 *  -Dxwork.profile.mintime=10000
 * 
 * 
 * 
* * * * One could extends the profiling feature provided by Struts2 in their web application as well. * * * *
 * 
 * 
 *    String logMessage = "Log message";
 *    UtilTimerStack.push(logMessage);
 *    try {
 *      // do some code
 *    }
 *    finally {
 *      UtilTimerStack.pop(logMessage); //this needs to be the same text as above
 *    }
 *    
 *    
 * 
* * or * *
 * 
 * 
 *   String result = UtilTimerStack.profile("purchaseItem: ", 
 *       new UtilTimerStack.ProfilingBlock() {
 *            public String doProfiling() {
 *               // do some code
 *               return "Ok";
 *            }
 *       });
 *       
 *       
 * 
* * * * * Profiled result is logged using commons-logging under the logger named * 'com.opensymphony.xwork2.util.profiling.UtilTimerStack'. Depending on the underlying logging implementation * say if it is Log4j, one could direct the log to appear in a different file, being emailed to someone or have * it stored in the db. * * * * @version $Date$ $Id$ */ public class UtilTimerStack { // A reference to the current ProfilingTimerBean protected static ThreadLocal current = new ThreadLocal(); /** * System property that controls whether this timer should be used or not. Set to "true" activates * the timer. Set to "false" to disactivate. */ public static final String ACTIVATE_PROPERTY = "xwork.profile.activate"; /** * System property that controls the min time, that if exceeded will cause a log (at INFO level) to be * created. */ public static final String MIN_TIME = "xwork.profile.mintime"; private static final Log log = LogFactory.getLog(UtilTimerStack.class); /** * Create and start a performance profiling with the name given. Deal with * profile hierarchy automatically, so caller don't have to be concern about it. * * @param name profile name */ public static void push(String name) { if (!isActive()) return; //create a new timer and start it ProfilingTimerBean newTimer = new ProfilingTimerBean(name); newTimer.setStartTime(); //if there is a current timer - add the new timer as a child of it ProfilingTimerBean currentTimer = (ProfilingTimerBean) current.get(); if (currentTimer != null) { currentTimer.addChild(newTimer); } //set the new timer to be the current timer current.set(newTimer); } /** * End a preformance profiling with the name given. Deal with * profile hierarchy automatically, so caller don't have to be concern about it. * * @param name profile name */ public static void pop(String name) { if (!isActive()) return; ProfilingTimerBean currentTimer = (ProfilingTimerBean) current.get(); //if the timers are matched up with each other (ie push("a"); pop("a")); if (currentTimer != null && name != null && name.equals(currentTimer.getResource())) { currentTimer.setEndTime(); ProfilingTimerBean parent = currentTimer.getParent(); //if we are the root timer, then print out the times if (parent == null) { printTimes(currentTimer); current.set(null); //for those servers that use thread pooling } else { current.set(parent); } } else { //if timers are not matched up, then print what we have, and then print warning. if (currentTimer != null) { printTimes(currentTimer); current.set(null); //prevent printing multiple times log.warn("Unmatched Timer. Was expecting " + currentTimer.getResource() + ", instead got " + name); } } } /** * Do a log (at INFO level) of the time taken for this particular profiling. * * @param currentTimer profiling timer bean */ private static void printTimes(ProfilingTimerBean currentTimer) { log.info(currentTimer.getPrintable(getMinTime())); } /** * Get the min time for this profiling, it searches for a System property * 'xwork.profile.mintime' and default to 0. * * @return long */ private static long getMinTime() { try { return Long.parseLong(System.getProperty(MIN_TIME, "0")); } catch (NumberFormatException e) { return -1; } } /** * Determine if profiling is being activated, by searching for a system property * 'xwork.profile.activate', default to false (profiling is off). * * @return true, if active, false otherwise. */ public static boolean isActive() { return System.getProperty(ACTIVATE_PROPERTY) != null; } /** * Turn profiling on or off. * * @param active */ public static void setActive(boolean active) { if (active) System.setProperty(ACTIVATE_PROPERTY, "true"); else System.clearProperty(ACTIVATE_PROPERTY); } /** * A convenience method that allows block of code subjected to profiling to be executed * and avoid the need of coding boiler code that does pushing (UtilTimeBean.push(...)) and * poping (UtilTimerBean.pop(...)) in a try ... finally ... block. * *

* * Example of usage: *

     * 	 // we need a returning result
     *   String result = UtilTimerStack.profile("purchaseItem: ", 
     *       new UtilTimerStack.ProfilingBlock() {
     *            public String doProfiling() {
     *               getMyService().purchaseItem(....)
     *               return "Ok";
     *            }
     *       });
     * 
* or *
     *   // we don't need a returning result
     *   UtilTimerStack.profile("purchaseItem: ", 
     *       new UtilTimerStack.ProfilingBlock() {
     *            public String doProfiling() {
     *               getMyService().purchaseItem(....)
     *               return null;
     *            }
     *       });
     * 
* * @param any return value if there's one. * @param name profile name * @param block code block subjected to profiling * @return T * @throws Exception */ public static T profile(String name, ProfilingBlock block) throws Exception { UtilTimerStack.push(name); try { return block.doProfiling(); } finally { UtilTimerStack.pop(name); } } /** * A callback interface where code subjected to profile is to be executed. This eliminates the need * of coding boiler code that does pushing (UtilTimerBean.push(...)) and poping (UtilTimerBean.pop(...)) * in a try ... finally ... block. * * @version $Date$ $Id$ * * @param */ public static interface ProfilingBlock { /** * Method that execute the code subjected to profiling. * * @return profiles Type * @throws Exception */ T doProfiling() throws Exception; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy