001    package biz.hammurapi.metrics.jmx;
002    
003    import java.util.Date;
004    import java.util.HashMap;
005    import java.util.Map;
006    
007    import javax.management.MBeanServer;
008    import javax.management.MalformedObjectNameException;
009    import javax.management.ObjectName;
010    import javax.management.StandardMBean;
011    
012    import biz.hammurapi.metrics.MeasurementCategoryFactory;
013    import biz.hammurapi.metrics.MeasurementConsumer;
014    import biz.hammurapi.metrics.SimpleSlice;
015    import biz.hammurapi.metrics.Slice;
016    
017    public abstract class JmxMeasurementCategoryFactory extends MeasurementCategoryFactory {
018            private String category;
019            private Integer interval;
020            
021            public void setCategory(String category) {
022                    this.category = category;
023            }
024            
025            public void setInterval(int pInterval) {
026                    this.interval = pInterval;
027            }
028            
029            private Map<String, MeasurementConsumer> measurementConsumers = new HashMap<String, MeasurementConsumer>();
030            
031            private class JmxSliceImpl implements JmxSlice {
032                    
033                    private String name;
034                    private Slice data;
035                    private long to;
036                    private Slice accumulator;
037    
038                    public JmxSliceImpl(String name) {
039                            this.name = name;
040                            data = new SimpleSlice(name);
041                            if (interval!=null) {
042                                    accumulator = new SimpleSlice(name);
043                                    to = System.currentTimeMillis();
044                            }
045                    }
046    
047                    public double getAverage() {
048                            return getData().getAvg();
049                    }
050    
051                    public double getDeviation() {
052                            return getData().getDeviation();
053                    }
054    
055                    public Date getFrom() {
056                            return new Date(getData().getFrom());
057                    }
058    
059                    public double getMax() {
060                            return getData().getMax();
061                    }
062    
063                    public double getMin() {
064                            return getData().getMin();
065                    }
066    
067                    public int getNumber() {
068                            return getData().getNumber();
069                    }
070    
071                    public Date getTo() {
072                            return new Date(getData().getTo());
073                    }
074    
075                    public double getTotal() {
076                            return getData().getTotal();
077                    }
078    
079                    public void reset() {
080                            data = new SimpleSlice(name);
081                    }
082                    
083                    Slice getData() {
084                            checkTime();
085                            return data;
086                    }
087    
088                    private void checkTime() {
089                            if (interval!=null) {
090                                    long now = System.currentTimeMillis();
091                                    if (now > to) {
092                                            data = accumulator;
093                                            accumulator = new SimpleSlice(name);
094                                            while (to<now) {
095                                                    to += interval;
096                                            }
097                                    }
098                            }
099                    }
100                    
101                    Slice getAccumulator() {
102                            checkTime();
103                            return interval==null ? data : accumulator;
104                    }
105                    
106            }
107    
108            public synchronized MeasurementConsumer getMeasurementConsumer(final String categoryName) {
109                    MBeanServer mBeanServer = getMBeanServer();
110                    if (mBeanServer!=null 
111                                    && (category==null || category.equals(categoryName) || (categoryName!=null && categoryName.startsWith(category+".")))) {
112                            MeasurementConsumer ret = (MeasurementConsumer) measurementConsumers.get(categoryName);
113                            if (ret==null) {                                                                
114                                    ret = new MeasurementConsumer() {
115                                            private Map<String, JmxSliceImpl> sliceMap = new HashMap<String, JmxSliceImpl>();
116    
117                                            public synchronized void addMeasurement(String name, double value, long time) {
118                                                    JmxSliceImpl slice = sliceMap.get(name);
119                                                    if (slice==null) {
120                                                            slice=new JmxSliceImpl(name);
121                                                            sliceMap.put(name, slice);
122                                                            
123                                                            try {
124                                                        MBeanServer mbs = getMBeanServer();
125                                                        if (mbs!=null) {
126                                                                mbs.registerMBean(new StandardMBean(slice, JmxSlice.class), objectName(categoryName, name));
127                                                        }
128                                                            } catch (Exception e) {
129                                                                    System.err.println("[JmxMeasurementCategoryFactory] ERROR: "+e);
130                                                                    return;
131                                                            }
132                                                    }
133                                                    slice.getAccumulator().add(value, time);
134                                            }
135                                            
136                                    };                              
137                            }
138                            return ret;             
139                    }
140                    return null;
141            }
142            
143            /**
144             * This implementation tries to use Java 5 management features.
145             * Returns null if JVM is not of version 5.
146             * @return MBean server to register MBeans with
147             */
148            protected abstract MBeanServer getMBeanServer();
149    
150            /**
151             * Constructs MBean name from category name and measurement name. 
152             * @param categoryName
153             * @param name
154             * @return
155             * @throws NullPointerException 
156             * @throws MalformedObjectNameException 
157             */
158            protected ObjectName objectName(final String categoryName, String name) throws MalformedObjectNameException {
159                    return new ObjectName("biz.hammurapi.metrics:category="+categoryName+",name="+name);
160            }
161    
162    }