/* * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.visualvm.modules.tracer.dynamic.jmx; import com.sun.tools.visualvm.application.Application; import com.sun.tools.visualvm.tools.jmx.JmxModel; import com.sun.tools.visualvm.tools.jmx.JmxModelFactory; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; import javax.management.Attribute; import javax.management.AttributeList; import javax.management.InstanceNotFoundException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.ReflectionException; import javax.management.RuntimeMBeanException; /** * A per application cached MBean attribute values provider<br/> * It uses a timestamp to decide whether fresh values should be retrieved * from the server. It also tries to batch the retrieval process to reduce * the network utilization overhead. * * @author Jaroslav Bachorik */ final public class JMXValueCache { final private static Map<Application, JMXValueCache> instanceMap = new WeakHashMap<Application, JMXValueCache>(); final private Map<ObjectName, Collection<String>> attributeMap = new HashMap<ObjectName, Collection<String>>(); final private Map<String, Object> valueMap = new HashMap<String, Object>(); final private MBeanServerConnection connection; volatile private long lastTimestamp = 0L; private JMXValueCache(Application app) { JmxModel model = JmxModelFactory.getJmxModelFor(app); connection = model.getMBeanServerConnection(); } public static JMXValueCache forApplication(Application app) { synchronized(instanceMap) { JMXValueCache cvp = instanceMap.get(app); if (cvp == null) { cvp = new JMXValueCache(app); instanceMap.put(app, cvp); } return cvp; } } public JMXValueCache register(ObjectName name, String attribute) { register(name, Collections.singleton(attribute)); return this; } public JMXValueCache register(ObjectName name, Collection<String> attributes) { synchronized(attributeMap) { Collection<String> existingAttribs = attributeMap.get(name); if (existingAttribs == null) { existingAttribs = new ArrayList<String>(); attributeMap.put(name, existingAttribs); } existingAttribs.addAll(attributes); lastTimestamp = -1; // need to clear the timestamp so the cache is loaded at the next getValue() request } return this; } public JMXValueCache unregister(ObjectName name, String attribute) { unregister(name, Collections.singleton(attribute)); return this; } public JMXValueCache unregister(ObjectName name, Collection<String> attributes) { synchronized(attributeMap) { Collection<String> existingAttribs = attributeMap.get(name); if (existingAttribs != null) { existingAttribs.removeAll(attributes); } } return this; } public MBeanAttributeInfo getInfo(ObjectName on, String attribute) { try { MBeanInfo mbeanInfo = connection.getMBeanInfo(on); for (MBeanAttributeInfo mbAttrInfo : mbeanInfo.getAttributes()) { if (mbAttrInfo.getName().equals(attribute)) { return mbAttrInfo; } } } catch (Exception e) { } return null; } public Object getValue(ObjectName name, String attribute, long timestamp) { refreshCache(timestamp); return valueMap.get(getId(name, attribute)); } private void refreshCache(long timestamp) { if (lastTimestamp == timestamp) { return; } lastTimestamp = timestamp; synchronized(attributeMap) { for(Map.Entry<ObjectName, Collection<String>> entry : attributeMap.entrySet()) { try { AttributeList al = connection.getAttributes(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()])); for(Attribute a : al.asList()) { valueMap.put(getId(entry.getKey(), a.getName()), a.getValue()); } continue; } catch (RuntimeMBeanException ex) { } catch (ReflectionException ex) { } catch (IOException ex) { } catch (InstanceNotFoundException e) { } for(String an : entry.getValue()) { String id = getId(entry.getKey(), an); if (!valueMap.containsKey(id)) valueMap.put(id, 0); } } } } private String getId(ObjectName on, String attrName) { return on.toString() + "#" + attrName; } }