2009/04/15 - Apache HiveMind has been retired.

For more information, please explore the Attic.

Clover coverage report - Code Coverage for hivemind-jmx release 1.2.1
Coverage timestamp: Fri Feb 10 2006 16:34:17 PST
file stats: LOC: 294   Methods: 13
NCLOC: 183   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
PerformanceMonitorMBean.java 68.2% 78.5% 76.9% 76%
coverage coverage
 1    // Copyright 2005 The Apache Software Foundation
 2    //
 3    // Licensed under the Apache License, Version 2.0 (the "License");
 4    // you may not use this file except in compliance with the License.
 5    // You may obtain a copy of the License at
 6    //
 7    // http://www.apache.org/licenses/LICENSE-2.0
 8    //
 9    // Unless required by applicable law or agreed to in writing, software
 10    // distributed under the License is distributed on an "AS IS" BASIS,
 11    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12    // See the License for the specific language governing permissions and
 13    // limitations under the License.
 14   
 15    package org.apache.hivemind.management.mbeans;
 16   
 17    import java.util.ArrayList;
 18    import java.util.HashMap;
 19    import java.util.Iterator;
 20    import java.util.List;
 21    import java.util.Map;
 22    import java.util.Set;
 23   
 24    import javax.management.AttributeNotFoundException;
 25    import javax.management.MBeanAttributeInfo;
 26    import javax.management.MBeanException;
 27    import javax.management.ReflectionException;
 28   
 29    import org.apache.hivemind.management.impl.PerformanceCollector;
 30    import org.apache.hivemind.service.MethodSignature;
 31   
 32    /**
 33    * MBean that holds and calculates the performance data for service method calls intercepted by the
 34    * {@link org.apache.hivemind.management.impl.PerformanceMonitorFactory performanceMonitor}
 35    * interceptor. Creates for each intercepted method 5 MBean attributes: Number of Calls, Minimum,
 36    * maximum, average and last execution time
 37    *
 38    * @author Achim Huegen
 39    * @since 1.1
 40    */
 41    public class PerformanceMonitorMBean extends AbstractDynamicMBean implements PerformanceCollector
 42    {
 43    protected static final String DATA_TYPE_MAXIMUM_TIME = "Maximum time";
 44   
 45    protected static final String DATA_TYPE_MINIMUM_TIME = "Minimum time";
 46   
 47    protected static final String DATA_TYPE_LAST_TIME = "Last time";
 48   
 49    protected static final String DATA_TYPE_AVERAGE_TIME = "Average time";
 50   
 51    protected static final String DATA_TYPE_COUNT = "Count";
 52   
 53    private Set _methods;
 54   
 55    private Map _countersByMethodSignature = new HashMap();
 56   
 57    private Map _countersByMethodId = new HashMap();
 58   
 59    private MBeanAttributeInfo[] _mBeanAttributeInfos;
 60   
 61    private Map _mBeanAttributeNameToCounterMap = new HashMap();
 62   
 63    /**
 64    * Creates a new instance
 65    *
 66    * @param methods
 67    * Set with instances of {@link org.apache.hivemind.service.MethodSignature}.
 68    * Contains the methods for that calls can be counted by this MBean
 69    */
 70  2 public PerformanceMonitorMBean(Set methods)
 71    {
 72  2 _methods = methods;
 73  2 initCounters();
 74    }
 75   
 76    /**
 77    * Builds two maps for accessing the counters by method signature and method id
 78    */
 79  2 protected void initCounters()
 80    {
 81  2 List mBeanAttributeInfoList = new ArrayList();
 82  2 for (Iterator methodIterator = _methods.iterator(); methodIterator.hasNext();)
 83    {
 84  6 MethodSignature method = (MethodSignature) methodIterator.next();
 85  6 Counter counter = new Counter();
 86  6 _countersByMethodSignature.put(method, counter);
 87  6 _countersByMethodId.put(method.getUniqueId(), counter);
 88   
 89  6 initAttributes(mBeanAttributeInfoList, counter, method);
 90    }
 91  2 _mBeanAttributeInfos = (MBeanAttributeInfo[]) mBeanAttributeInfoList
 92    .toArray(new MBeanAttributeInfo[mBeanAttributeInfoList.size()]);
 93    }
 94   
 95    /**
 96    * Creates for a intercepted method 5 MBean attributes: Number of Calls, Minimum, maximum,
 97    * average and last execution time
 98    */
 99  6 protected void initAttributes(List mBeanAttributeInfoList, Counter counter, MethodSignature method)
 100    {
 101  6 addAttribute(
 102    mBeanAttributeInfoList, counter,
 103    method,
 104    Long.class,
 105    DATA_TYPE_COUNT,
 106    "Number of method calls for method " + method);
 107  6 addAttribute(
 108    mBeanAttributeInfoList, counter,
 109    method,
 110    Long.class,
 111    DATA_TYPE_AVERAGE_TIME,
 112    "Average execution time in ms of method " + method);
 113  6 addAttribute(
 114    mBeanAttributeInfoList, counter,
 115    method,
 116    Long.class,
 117    DATA_TYPE_LAST_TIME,
 118    "Last execution time in ms of method " + method);
 119  6 addAttribute(
 120    mBeanAttributeInfoList, counter,
 121    method,
 122    Long.class,
 123    DATA_TYPE_MINIMUM_TIME,
 124    "Minimum execution time in ms of method " + method);
 125  6 addAttribute(
 126    mBeanAttributeInfoList, counter,
 127    method,
 128    Long.class,
 129    DATA_TYPE_MAXIMUM_TIME,
 130    "Maximum execution time in ms of method " + method);
 131   
 132    }
 133   
 134    /**
 135    * Creates a new MBean Attribute for a performance counter
 136    */
 137  30 private void addAttribute(List mBeanAttributeInfoList, Counter counter, MethodSignature method,
 138    Class attributeType, String performanceDataType, String description)
 139    {
 140  30 String attributeName = null;
 141  30 MBeanAttributeInfo attributeInfo = null;
 142  30 try
 143    {
 144  30 attributeName = buildAttributeName(method, performanceDataType);
 145  30 attributeInfo = new MBeanAttributeInfo(attributeName, attributeType.getName(), description,
 146    true, false, false);
 147    }
 148    catch (IllegalArgumentException e)
 149    {
 150    // Some jmx implementations (jboss 3.2.7) don't accept spaces and braces
 151    // in attribute names. In this case a fallback is executed, that replaces
 152    // invalid chars by underscores.
 153  0 attributeName = buildAttributeNameDefensive(method, performanceDataType);
 154  0 attributeInfo = new MBeanAttributeInfo(attributeName, attributeType.getName(), description,
 155    true, false, false);
 156    }
 157  30 mBeanAttributeInfoList.add(attributeInfo);
 158  30 AttributeToCounterLink atcLink = new AttributeToCounterLink(counter, performanceDataType);
 159  30 _mBeanAttributeNameToCounterMap.put(attributeName, atcLink);
 160    }
 161   
 162    /**
 163    * Replaces all chars in a string which are not valid in a java identifier with underscores
 164    */
 165  0 private String makeValidJavaIdentifier(String attributeName)
 166    {
 167  0 StringBuffer result = new StringBuffer();
 168  0 for (int i = 0; i < attributeName.length(); i++)
 169    {
 170  0 char currentChar = attributeName.charAt(i);
 171  0 if (Character.isJavaIdentifierPart(currentChar))
 172  0 result.append(currentChar);
 173  0 else result.append('_');
 174    }
 175  0 return result.toString();
 176    }
 177   
 178    /**
 179    * Builds the attribute name that holds the measurement data of type
 180    * <code>performanceDataType</code> for the method.
 181    */
 182  35 protected String buildAttributeName(MethodSignature method, String performanceDataType)
 183    {
 184  35 String attributeName = method.getUniqueId() + " : " + performanceDataType;
 185  35 return attributeName;
 186    }
 187   
 188    /**
 189    * Builds the attribute name that holds the measurement data of type.
 190    * <code>performanceDataType</code> for the method.
 191    * Some jmx implementations (jboss 3.2.7) don't accept spaces and braces in attribute names.
 192    * Unlike {@link #buildAttributeName(MethodSignature, String)} this method doesn't
 193    * use chars that are not accepted by {@link Character#isJavaIdentifierPart(char)}.
 194    */
 195  0 protected String buildAttributeNameDefensive(MethodSignature method, String performanceDataType)
 196    {
 197  0 String attributeName = method.getUniqueId() + "$[" + performanceDataType;
 198  0 return makeValidJavaIdentifier(attributeName);
 199    }
 200   
 201    /**
 202    * @see PerformanceCollector#addMeasurement(MethodSignature, long)
 203    */
 204  5 public void addMeasurement(MethodSignature method, long executionTime)
 205    {
 206  5 Counter counter = (Counter) _countersByMethodSignature.get(method);
 207  5 counter.addMeasurement(executionTime);
 208    }
 209   
 210  1 protected MBeanAttributeInfo[] createMBeanAttributeInfo()
 211    {
 212  1 return _mBeanAttributeInfos;
 213    }
 214   
 215    /**
 216    * @see AbstractDynamicMBean#getAttribute(java.lang.String)
 217    */
 218  5 public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException,
 219    ReflectionException
 220    {
 221    // Split the attribute to get method id and performance data type separately
 222  5 AttributeToCounterLink atcLink = (AttributeToCounterLink) _mBeanAttributeNameToCounterMap.get(attribute);
 223  5 if (atcLink == null)
 224  0 throw new AttributeNotFoundException("Attribute '" + attribute + "' not found");
 225   
 226  5 String type = atcLink.type;
 227  5 Counter counter = atcLink.counter;
 228  5 if (type.equals(DATA_TYPE_COUNT))
 229  1 return new Long(counter.count);
 230  4 else if (type.equals(DATA_TYPE_AVERAGE_TIME))
 231  1 return new Long(counter.average);
 232  3 else if (type.equals(DATA_TYPE_LAST_TIME))
 233  1 return new Long(counter.last);
 234  2 else if (type.equals(DATA_TYPE_MINIMUM_TIME))
 235  1 return new Long(counter.min);
 236  1 else if (type.equals(DATA_TYPE_MAXIMUM_TIME))
 237  1 return new Long(counter.max);
 238    else
 239  0 throw new IllegalArgumentException("Unknown performance data type");
 240    }
 241   
 242    }
 243   
 244    /**
 245    * Class that holds and calculates the performance data for a single method
 246    */
 247   
 248    class Counter
 249    {
 250    long count = 0;
 251   
 252    long last = 0;
 253   
 254    long average = 0;
 255   
 256    long max = 0;
 257   
 258    long min = 0;
 259   
 260  0 public String toString()
 261    {
 262  0 return "" + count;
 263    }
 264   
 265    /**
 266    * Should be synchronized, but this could slow things really down
 267    *
 268    * @param executionTime
 269    */
 270  5 public void addMeasurement(long executionTime)
 271    {
 272  5 count++;
 273  5 last = executionTime;
 274    // not an exact value without a complete history and stored as long
 275  5 average = (average * (count - 1) + executionTime) / count;
 276  5 if (executionTime < min || min == 0)
 277  5 min = executionTime;
 278  5 if (executionTime > max || max == 0)
 279  3 max = executionTime;
 280    }
 281    }
 282   
 283    class AttributeToCounterLink
 284    {
 285    Counter counter;
 286   
 287    String type;
 288   
 289  30 public AttributeToCounterLink(Counter counter, String type)
 290    {
 291  30 this.counter = counter;
 292  30 this.type = type;
 293    }
 294    }