/* * Galaxy * Copyright (c) 2012-2014, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.galaxy.core; import co.paralleluniverse.galaxy.Cluster; import co.paralleluniverse.galaxy.cluster.LifecycleListener; import co.paralleluniverse.galaxy.cluster.NodeChangeListener; import co.paralleluniverse.galaxy.cluster.NodeInfo; import co.paralleluniverse.galaxy.cluster.SlaveConfigurationListener; import co.paralleluniverse.galaxy.monitoring.ClusterMXBean; import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import javax.management.AttributeChangeNotification; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.MBeanNotificationInfo; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; import javax.management.NotificationEmitter; import javax.management.ObjectName; import javax.management.StandardEmitterMBean; /** * * @author pron */ public class ClusterMonitor extends StandardEmitterMBean implements ClusterMXBean, LifecycleListener, NodeChangeListener, SlaveConfigurationListener, NotificationEmitter { private final String name; private final Cluster cluster; private boolean registered; private int notificationSequenceNumber; public ClusterMonitor(Cluster cluster) { super(ClusterMXBean.class, true, new NotificationBroadcasterSupport()); this.name = "co.paralleluniverse.galaxy:type=Cluster"; this.cluster = cluster; registerMBean(); } private void registerMBean() { try { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); ObjectName mxbeanName = new ObjectName(name); mbs.registerMBean(this, mxbeanName); this.registered = true; } catch (InstanceAlreadyExistsException ex) { throw new RuntimeException(ex); } catch (MBeanRegistrationException ex) { throw new RuntimeException(ex); } catch (NotCompliantMBeanException ex) { throw new AssertionError(ex); } catch (MalformedObjectNameException ex) { throw new AssertionError(ex); } } public void unregisterMBean() { try { if (registered) ManagementFactory.getPlatformMBeanServer().unregisterMBean(new ObjectName(name)); this.registered = false; } catch (InstanceNotFoundException ex) { throw new RuntimeException(ex); } catch (MBeanRegistrationException ex) { throw new RuntimeException(ex); } catch (MalformedObjectNameException ex) { throw new AssertionError(ex); } } @Override public synchronized MBeanNotificationInfo[] getNotificationInfo() { String[] types = new String[]{ AttributeChangeNotification.ATTRIBUTE_CHANGE }; String _name = AttributeChangeNotification.class.getName(); String description = "An attribute of this MBean has changed"; MBeanNotificationInfo info = new MBeanNotificationInfo(types, _name, description); return new MBeanNotificationInfo[]{info}; } @Override public SortedMap<String, String> getMyNodeInfo() { return toMap(cluster.getMyNodeInfo()); } @Override public boolean isOnline() { return cluster.isOnline(); } @Override public boolean isMaster() { return cluster.isMaster(); } @Override public void shutdown() { cluster.goOffline(); } @Override public boolean hasServer() { return cluster.hasServer(); } @Override public List<SortedMap<String, String>> getNodes() { return toMapList(cluster.getMasters()); } @Override public SortedMap<String, String> getMyMaster() { return toMap(cluster.getMyMaster()); } @Override public List<SortedMap<String, String>> getMySlaves() { return toMapList(cluster.getMySlaves()); } private List<SortedMap<String, String>> toMapList(Collection<NodeInfo> nis) { SortedSet<NodeInfo> nis1 = new TreeSet<NodeInfo>(new Comparator<NodeInfo>() { @Override public int compare(NodeInfo o1, NodeInfo o2) { return o1.getNodeId() - o2.getNodeId(); } }); nis1.addAll(nis); List<SortedMap<String, String>> list = new ArrayList<SortedMap<String, String>>(nis.size()); for (NodeInfo ni : nis1) list.add(toMap(ni)); return list; } private SortedMap<String, String> toMap(NodeInfo ni) { SortedMap<String, String> map = new TreeMap<String, String>(); map.put("_id", Short.toString(ni.getNodeId())); map.put("_name", ni.getName()); for (String p : ni.getProperties()) map.put(p, ni.get(p).toString()); return map; } private void notifyAttributeChange(String message, String attrName) { try { Object newValue = this.getAttribute(attrName); Notification n = new AttributeChangeNotification(this, notificationSequenceNumber++, System.currentTimeMillis(), message, attrName, null, null, newValue); sendNotification(n); } catch (Exception ex) { ex.printStackTrace(); } } @Override public void joinedCluster() { notifyAttributeChange("Now joined", "online"); } @Override public void offline() { notifyAttributeChange("Now offline", "online"); } @Override public void online(boolean master) { notifyAttributeChange("Now online as " + (master ? "master" : "slave"), "online"); } @Override public void switchToMaster() { notifyAttributeChange("Switched to master", "master"); } @Override public void nodeAdded(short id) { notifyAttributeChange("Node " + id + " added", "nodes"); } @Override public void nodeRemoved(short id) { notifyAttributeChange("Node " + id + " removed", "nodes"); } @Override public void nodeSwitched(short id) { notifyAttributeChange("Node " + id + " switched", "nodes"); } @Override public void newMaster(NodeInfo node) { notifyAttributeChange("New master", "myMaster"); } @Override public void slaveAdded(NodeInfo node) { notifyAttributeChange("Slave added", "mySlaves"); } @Override public void slaveRemoved(NodeInfo node) { notifyAttributeChange("Slave removed", "mySlaves"); } }