Mercurial > hg > release > thermostat-0.15
view vm-jmx/agent/src/main/java/com/redhat/thermostat/vm/jmx/agent/internal/JmxBackend.java @ 1248:84ea87a65eda
Use WriterID service over Storage.get/setAgentId() (Part 3).
Reviewed-by: vanaltj
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-September/008099.html
PR1509
author | Severin Gehwolf <sgehwolf@redhat.com> |
---|---|
date | Mon, 02 Sep 2013 11:32:11 +0200 |
parents | ba8a0e50ddee |
children |
line wrap: on
line source
/* * Copyright 2012, 2013 Red Hat, Inc. * * This file is part of Thermostat. * * Thermostat is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * Thermostat 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 for more details. * * You should have received a copy of the GNU General Public License * along with Thermostat; see the file COPYING. If not see * <http://www.gnu.org/licenses/>. * * Linking this code with other modules is making a combined work * based on this code. Thus, the terms and conditions of the GNU * General Public License cover the whole combination. * * As a special exception, the copyright holders of this code give * you permission to link this code with independent modules to * produce an executable, regardless of the license terms of these * independent modules, and to copy and distribute the resulting * executable under terms of your choice, provided that you also * meet, for each linked independent module, the terms and conditions * of the license of that module. An independent module is a module * which is not derived from or based on this code. If you modify * this code, you may extend this exception to your version of the * library, but you are not obligated to do so. If you do not wish * to do so, delete this exception statement from your version. */ package com.redhat.thermostat.vm.jmx.agent.internal; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.management.InstanceNotFoundException; import javax.management.IntrospectionException; import javax.management.MBeanServerConnection; import javax.management.MBeanServerDelegate; import javax.management.MBeanServerNotification; import javax.management.Notification; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.ReflectionException; import com.redhat.thermostat.agent.command.ReceiverRegistry; import com.redhat.thermostat.agent.command.RequestReceiver; import com.redhat.thermostat.backend.BaseBackend; import com.redhat.thermostat.common.Clock; import com.redhat.thermostat.common.SystemClock; import com.redhat.thermostat.common.Version; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.utils.management.MXBeanConnection; import com.redhat.thermostat.utils.management.MXBeanConnectionPool; import com.redhat.thermostat.vm.jmx.common.JmxNotification; import com.redhat.thermostat.vm.jmx.common.JmxNotificationDAO; import com.redhat.thermostat.vm.jmx.common.JmxNotificationStatus; public class JmxBackend extends BaseBackend { private static final Logger logger = LoggingUtils.getLogger(JmxBackend.class); private final ReceiverRegistry registry; private final RequestReceiver receiver; private final JmxNotificationDAO dao; private final MXBeanConnectionPool pool; private final Clock clock; private final NotificationListener registrationNotificationListener; private final NotificationListener notificationWriter; private final Map<Integer, MXBeanConnection> connections = new HashMap<>(); private final WriterID writerId; private boolean isActive = false; // Used as a callback handler private static class VmIdAndPid { public final String vmId; public final int pid; public VmIdAndPid(String vmId, int pid) { this.vmId = vmId; this.pid = pid; } } public JmxBackend(Version version, ReceiverRegistry registry, JmxNotificationDAO dao, MXBeanConnectionPool pool, RequestReceiver receiver, WriterID writerId) { this(version, registry, dao, pool, receiver, new SystemClock(), writerId); } public JmxBackend(Version version, ReceiverRegistry registry, JmxNotificationDAO dao, MXBeanConnectionPool pool, RequestReceiver receiver, Clock clock, WriterID writerId) { super("VM JMX Backend", "gathers JMX information using JMX", "Red Hat, Inc.", version.getVersionNumber()); this.registry = registry; this.pool = pool; this.dao = dao; this.clock = clock; this.writerId = writerId; this.registrationNotificationListener = new RegistrationNotificationListener(); this.notificationWriter = new NotificationWriter(); this.receiver = receiver; } @Override public int getOrderValue() { return ORDER_USER_GROUP + 99; } @Override public boolean activate() { if (isActive) { return true; } registry.registerReceiver(receiver); isActive = true; return isActive; } @Override public boolean deactivate() { if (!isActive) { return true; } registry.unregisterReceivers(); isActive = false; return true; } @Override public boolean isActive() { return isActive; } public void enableNotificationsFor(String vmId, int pid) { VmIdAndPid idAndPid = new VmIdAndPid(vmId, pid); try { MXBeanConnection connection = pool.acquire(pid); connections.put(pid, connection); MBeanServerConnection server = connection.get(); Set<ObjectName> names = server.queryNames(null, null); for (ObjectName name : names) { if (name.equals(MBeanServerDelegate.DELEGATE_NAME)) { server.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, this.registrationNotificationListener, null, idAndPid); } else { addNotificationListenerToMBean(idAndPid, server, name); } } String wId = writerId.getWriterID(); JmxNotificationStatus update = new JmxNotificationStatus(wId); update.setVmId(vmId); update.setEnabled(true); update.setTimeStamp(clock.getRealTimeMillis()); dao.addNotificationStatus(update); } catch (Exception e) { logger.log(Level.WARNING, "Unable to connect to the mx bean connector", e); } } public void disableNotificationsFor(String vmId, int pid) { MXBeanConnection connection = connections.get(pid); String wId = writerId.getWriterID(); JmxNotificationStatus update = new JmxNotificationStatus(wId); update.setVmId(vmId); update.setEnabled(false); update.setTimeStamp(clock.getRealTimeMillis()); dao.addNotificationStatus(update); try { pool.release(pid, connection); } catch (Exception e) { logger.warning("Unable to release mx bean connection"); } } private class RegistrationNotificationListener implements NotificationListener { @Override public void handleNotification(Notification notification, Object handback) { VmIdAndPid idAndPid = (VmIdAndPid) handback; MBeanServerConnection server = connections.get(idAndPid.pid).get(); MBeanServerNotification serverNotification = (MBeanServerNotification) notification; ObjectName name = serverNotification.getMBeanName(); try { if (MBeanServerNotification.REGISTRATION_NOTIFICATION.equals(serverNotification.getType())) { logger.fine("MBean Registered: " + name); addNotificationListenerToMBean(idAndPid, server, name); } else if (MBeanServerNotification.UNREGISTRATION_NOTIFICATION.equals(serverNotification.getType())) { logger.fine("MBean Unregistered: " + name); // we should remove the listener, but the object is not // around to emit notifications } } catch (IOException | InstanceNotFoundException | IntrospectionException | ReflectionException e) { logger.log(Level.WARNING, "exception while handling MBeanServerNotification", e); } } } // Writes the notification to storage private class NotificationWriter implements NotificationListener { @Override public void handleNotification(Notification notification, Object handback) { VmIdAndPid idAndPid = (VmIdAndPid) handback; String wId = writerId.getWriterID(); JmxNotification data = new JmxNotification(wId); data.setVmId(idAndPid.vmId); data.setTimeStamp(notification.getTimeStamp()); data.setSourceBackend(JmxBackend.class.getName()); data.setSourceDetails(((ObjectName) notification.getSource()).getCanonicalName()); data.setContents(notification.getMessage()); dao.addNotification(data); } } private void addNotificationListenerToMBean(VmIdAndPid idAndPid, MBeanServerConnection server, ObjectName name) throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException { if (server.getMBeanInfo(name).getNotifications().length > 0) { server.addNotificationListener(name, JmxBackend.this.notificationWriter, null, idAndPid); } } }