blob: 5fe667c0feb20f000d1363bc84da11f34ff272cf [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.qi4j.library.jmx;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.management.*;
import org.slf4j.LoggerFactory;
/**
* TODO
*/
public class MBeanTracker
{
private boolean started = false;
private ObjectName pattern;
private MBeanServer server;
private List<TrackerCallback> callbacks = new ArrayList<TrackerCallback>();
private List<ObjectName> tracked = Collections.synchronizedList( new ArrayList<ObjectName>() );
private RegistrationListener registrationListener;
public MBeanTracker(ObjectName pattern, MBeanServer server)
{
this.pattern = pattern;
this.server = server;
}
public MBeanTracker registerCallback(TrackerCallback callback)
{
List<TrackerCallback> newList = new ArrayList<TrackerCallback>(callbacks);
newList.add(callback);
callbacks = newList;
return this;
}
public MBeanTracker unregisterCallback(TrackerCallback callback)
{
List<TrackerCallback> newList = new ArrayList<TrackerCallback>(callbacks);
newList.remove(callback);
callbacks = newList;
return this;
}
public Iterable<ObjectName> getTracked()
{
return tracked;
}
public void start()
{
if (!started)
{
try
{
registrationListener = new RegistrationListener();
server.addNotificationListener(new ObjectName("JMImplementation:type=MBeanServerDelegate"), registrationListener, null, null);
for (ObjectName objectName : server.queryNames(pattern, null))
{
for (TrackerCallback callback : callbacks)
{
try
{
tracked.add(objectName);
callback.addedMBean(objectName, server);
} catch (Throwable throwable)
{
LoggerFactory.getLogger( MBeanTracker.class ).error("Tracker callback threw exception", throwable);
}
}
}
started = true;
} catch (Exception e)
{
// Could not start
}
}
}
public void stop()
{
if (started)
{
try
{
server.removeNotificationListener(new ObjectName("JMImplementation:type=MBeanServerDelegate"), registrationListener);
for (ObjectName objectName : server.queryNames(pattern, null))
{
for (TrackerCallback callback : callbacks)
{
try
{
callback.removedMBean(objectName, server);
tracked.remove(objectName);
} catch (Throwable throwable)
{
LoggerFactory.getLogger(MBeanTracker.class).error("Tracker callback threw exception", throwable);
}
}
}
started = false;
} catch (Exception e)
{
// Could not start
}
}
}
/**
* Callback that is used to notify when MBeans matching the given pattern becomes
* added or removed.
*/
public interface TrackerCallback
{
void addedMBean(ObjectName newMBean, MBeanServer server)
throws Throwable;
void removedMBean(ObjectName removedMBean, MBeanServer server)
throws Throwable;
}
/**
* Registers the given NotificationListener+NotificationFilter on tracked MBeans.
*/
public static class NotificationTracker
implements TrackerCallback
{
private NotificationListener listener;
private NotificationFilter filter;
public NotificationTracker( NotificationListener listener, NotificationFilter filter )
{
this.listener = listener;
this.filter = filter;
}
@Override
public void addedMBean( ObjectName newMBean, MBeanServer server ) throws Throwable
{
server.addNotificationListener( newMBean, listener, filter, null);
}
@Override
public void removedMBean( ObjectName removedMBean, MBeanServer server ) throws Throwable
{
server.removeNotificationListener( removedMBean, listener );
}
}
private class RegistrationListener
implements NotificationListener
{
@Override
public void handleNotification(Notification notification, Object o)
{
if (notification instanceof MBeanServerNotification )
{
MBeanServerNotification serverNotification = (MBeanServerNotification) notification;
if (pattern.apply(serverNotification.getMBeanName()))
{
if (serverNotification.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION))
{
for (TrackerCallback callback : callbacks)
{
try
{
tracked.add(serverNotification.getMBeanName());
callback.addedMBean(serverNotification.getMBeanName(), server);
} catch (Throwable throwable)
{
LoggerFactory.getLogger(MBeanTracker.class).error("Tracker callback threw exception", throwable);
}
}
} else if (serverNotification.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION))
{
for (TrackerCallback callback : callbacks)
{
try
{
callback.removedMBean(serverNotification.getMBeanName(), server);
tracked.remove(serverNotification.getMBeanName());
} catch (Throwable throwable)
{
LoggerFactory.getLogger(MBeanTracker.class).error("Tracker callback threw exception", throwable);
}
}
}
}
}
}
}
}