// ********************************************************************** // // Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** package IceInternal; public class MetricsMap { public class Entry { Entry(T obj) { _object = obj; } public void failed(String exceptionName) { synchronized(MetricsMap.this) { ++_object.failures; if(_failures == null) { _failures = new java.util.HashMap(); } Integer count = _failures.get(exceptionName); _failures.put(exceptionName, new Integer(count == null ? 1 : count + 1)); } } @SuppressWarnings("unchecked") public MetricsMap.Entry getMatching(String mapName, IceMX.MetricsHelper helper, Class cl) { SubMap m; synchronized(MetricsMap.this) { m = _subMaps != null ? (SubMap)_subMaps.get(mapName) : null; if(m == null) { m = createSubMap(mapName, cl); if(m == null) { return null; } if(_subMaps == null) { _subMaps = new java.util.HashMap>(); } _subMaps.put(mapName, m); } } return m.getMatching(helper); } public void detach(long lifetime) { synchronized(MetricsMap.this) { _object.totalLifetime += lifetime; if(--_object.current == 0) { detached(this); } } } public void execute(IceMX.Observer.MetricsUpdate func) { synchronized(MetricsMap.this) { func.update(_object); } } public MetricsMap getMap() { return MetricsMap.this; } private IceMX.MetricsFailures getFailures() { if(_failures == null) { return null; } IceMX.MetricsFailures f = new IceMX.MetricsFailures(); f.id = _object.id; f.failures = new java.util.HashMap(_failures); return f; } private void attach(IceMX.MetricsHelper helper) { ++_object.total; ++_object.current; helper.initMetrics(_object); } private boolean isDetached() { return _object.current == 0; } @SuppressWarnings("unchecked") public IceMX.Metrics clone() { T metrics = (T)_object.clone(); if(_subMaps != null) { for(SubMap s : _subMaps.values()) { s.addSubMapToMetrics(metrics); } } return metrics; } private T _object; private java.util.Map _failures; private java.util.Map> _subMaps; }; static class SubMap { public SubMap(MetricsMap map, java.lang.reflect.Field field) { _map = map; _field = field; } public MetricsMap.Entry getMatching(IceMX.MetricsHelper helper) { return _map.getMatching(helper, null); } public void addSubMapToMetrics(IceMX.Metrics metrics) { try { _field.set(metrics, _map.getMetrics()); } catch(Exception ex) { assert(false); } } final private MetricsMap _map; final private java.lang.reflect.Field _field; }; static class SubMapCloneFactory { public SubMapCloneFactory(MetricsMap map, java.lang.reflect.Field field) { _map = map; _field = field; } public SubMap create() { return new SubMap(new MetricsMap(_map), _field); } final private MetricsMap _map; final private java.lang.reflect.Field _field; }; static class SubMapFactory { SubMapFactory(Class cl, java.lang.reflect.Field field) { _class = cl; _field = field; } SubMapCloneFactory createCloneFactory(String subMapPrefix, Ice.Properties properties) { return new SubMapCloneFactory(new MetricsMap(subMapPrefix, _class, properties, null), _field); } final private Class _class; final private java.lang.reflect.Field _field; }; MetricsMap(String mapPrefix, Class cl, Ice.Properties props, java.util.Map> subMaps) { MetricsAdminI.validateProperties(mapPrefix, props); _properties = props.getPropertiesForPrefix(mapPrefix); _retain = props.getPropertyAsIntWithDefault(mapPrefix + "RetainDetached", 10); _accept = parseRule(props, mapPrefix + "Accept"); _reject = parseRule(props, mapPrefix + "Reject"); _groupByAttributes = new java.util.ArrayList(); _groupBySeparators = new java.util.ArrayList(); _class = cl; String groupBy = props.getPropertyWithDefault(mapPrefix + "GroupBy", "id"); if(!groupBy.isEmpty()) { String v = ""; boolean attribute = Character.isLetter(groupBy.charAt(0)) || Character.isDigit(groupBy.charAt(0)); if(!attribute) { _groupByAttributes.add(""); } for(char p : groupBy.toCharArray()) { boolean isAlphaNum = Character.isLetter(p) || Character.isDigit(p) || p == '.'; if(attribute && !isAlphaNum) { _groupByAttributes.add(v); v = "" + p; attribute = false; } else if(!attribute && isAlphaNum) { _groupBySeparators.add(v); v = "" + p; attribute = true; } else { v += p; } } if(attribute) { _groupByAttributes.add(v); } else { _groupBySeparators.add(v); } } if(subMaps != null && !subMaps.isEmpty()) { _subMaps = new java.util.HashMap>(); java.util.List subMapNames = new java.util.ArrayList(); for(java.util.Map.Entry> e : subMaps.entrySet()) { subMapNames.add(e.getKey()); String subMapsPrefix = mapPrefix + "Map."; String subMapPrefix = subMapsPrefix + e.getKey() + '.'; if(props.getPropertiesForPrefix(subMapPrefix).isEmpty()) { if(props.getPropertiesForPrefix(subMapsPrefix).isEmpty()) { subMapPrefix = mapPrefix; } else { continue; // This sub-map isn't configured. } } _subMaps.put(e.getKey(), e.getValue().createCloneFactory(subMapPrefix, props)); } } else { _subMaps = null; } } MetricsMap(MetricsMap map) { _properties = map._properties; _groupByAttributes = map._groupByAttributes; _groupBySeparators = map._groupBySeparators; _retain = map._retain; _accept = map._accept; _reject = map._reject; _class = map._class; _subMaps = map._subMaps; } java.util.Map getProperties() { return _properties; } synchronized IceMX.Metrics[] getMetrics() { IceMX.Metrics[] metrics = new IceMX.Metrics[_objects.size()]; int i = 0; for(Entry e : _objects.values()) { metrics[i++] = e.clone(); } return metrics; } synchronized IceMX.MetricsFailures[] getFailures() { java.util.List failures = new java.util.ArrayList(); for(Entry e : _objects.values()) { IceMX.MetricsFailures f = e.getFailures(); if(f != null) { failures.add(f); } } return failures.toArray(new IceMX.MetricsFailures[failures.size()]); } synchronized IceMX.MetricsFailures getFailures(String id) { Entry e = _objects.get(id); if(e != null) { return e.getFailures(); } return null; } @SuppressWarnings("unchecked") public SubMap createSubMap(String subMapName, Class cl) { if(_subMaps == null) { return null; } SubMapCloneFactory factory = (SubMapCloneFactory)_subMaps.get(subMapName); if(factory != null) { return factory.create(); } return null; } public Entry getMatching(IceMX.MetricsHelper helper, Entry previous) { // // Check the accept and reject filters. // for(java.util.Map.Entry e : _accept.entrySet()) { if(!match(e.getKey(), e.getValue(), helper, false)) { return null; } } for(java.util.Map.Entry e : _reject.entrySet()) { if(match(e.getKey(), e.getValue(), helper, true)) { return null; } } // // Compute the key from the GroupBy property. // String key; try { if(_groupByAttributes.size() == 1) { key = helper.resolve(_groupByAttributes.get(0)); } else { StringBuilder os = new StringBuilder(); java.util.Iterator q = _groupBySeparators.iterator(); for(String p : _groupByAttributes) { os.append(helper.resolve(p)); if(q.hasNext()) { os.append(q.next()); } } key = os.toString(); } } catch(Exception ex) { return null; } // // Lookup the metrics object. // synchronized(this) { if(previous != null && previous._object.id.equals(key)) { assert(_objects.get(key) == previous); return previous; } Entry e = _objects.get(key); if(e == null) { try { T t = _class.newInstance(); t.id = key; e = new Entry(t); _objects.put(key, e); } catch(Exception ex) { assert(false); } } e.attach(helper); return e; } } private void detached(Entry entry) { if(_retain == 0) { return; } if(_detachedQueue == null) { _detachedQueue = new java.util.LinkedList(); } assert(_detachedQueue.size() <= _retain); // Compress the queue by removing entries which are no longer detached. java.util.Iterator p = _detachedQueue.iterator(); while(p.hasNext()) { Entry e = p.next(); if(e == entry || !e.isDetached()) { p.remove(); } } // If there's still no room, remove the oldest entry (at the front). if(_detachedQueue.size() == _retain) { _objects.remove(_detachedQueue.pollFirst()._object.id); } // Add the entry at the back of the queue. _detachedQueue.add(entry); } private java.util.Map parseRule(Ice.Properties properties, String name) { java.util.Map pats = new java.util.HashMap(); java.util.Map rules = properties.getPropertiesForPrefix(name + '.'); for(java.util.Map.Entry e : rules.entrySet()) { pats.put(e.getKey().substring(name.length() + 1), java.util.regex.Pattern.compile(e.getValue())); } return pats; } private boolean match(String attribute, java.util.regex.Pattern regex, IceMX.MetricsHelper helper, boolean reject) { String value; try { value = helper.resolve(attribute); } catch(Exception ex) { return !reject; } return regex.matcher(value).matches(); } final private java.util.Map _properties; final private java.util.List _groupByAttributes; final private java.util.List _groupBySeparators; final private int _retain; final private java.util.Map _accept; final private java.util.Map _reject; final private Class _class; final private java.util.Map _objects = new java.util.HashMap(); final private java.util.Map> _subMaps; private java.util.Deque _detachedQueue; };