com.caucho.jmx.MBeanContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of resin-kernel Show documentation
Show all versions of resin-kernel Show documentation
Kernel for Resin Java Application Server
The newest version!
/*
* Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source 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 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.jmx;
import com.caucho.loader.*;
import com.caucho.util.L10N;
import javax.management.*;
import javax.management.loading.ClassLoaderRepository;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.logging.*;
import java.io.Closeable;
/**
* The context containing mbeans registered at a particular level.
*/
public class MBeanContext
{
private static final Logger log
= Logger.getLogger(MBeanContext.class.getName());
private static final L10N L = new L10N(MBeanContext.class);
/*
private final EnvironmentLocal _mbeanClose
= new EnvironmentLocal();
*/
private MBeanContext _parent;
// The owning MBeanServer
private AbstractMBeanServer _mbeanServer;
private MBeanContext _globalContext;
private MBeanServerDelegate _delegate;
private long _seq;
// class loader for this server
private ClassLoader _loader;
private String _domain = "resin";
private LinkedHashMap _properties
= new LinkedHashMap();
private ClassLoaderRepositoryImpl _classLoaderRepository
= new ClassLoaderRepositoryImpl();
// map of all mbeans
private Hashtable _mbeans
= new Hashtable();
private ArrayList _listeners = new ArrayList();
// The local view associated with the context
private MBeanView _view;
// The global view associated with the context
private MBeanView _globalView;
MBeanContext(AbstractMBeanServer mbeanServer,
ClassLoader loader,
MBeanServerDelegate delegate,
MBeanContext globalContext)
{
loader = Environment.getEnvironmentClassLoader(loader);
if (loader == null)
loader = ClassLoader.getSystemClassLoader();
_mbeanServer = mbeanServer;
_loader = loader;
_delegate = delegate;
_globalContext = globalContext;
_mbeanServer.setCurrentContext(this, loader);
Environment.addClassLoaderListener(new CloseListener(this), _loader);
//Environment.addClassLoaderListener(new WeakCloseListener(this), _loader);
_classLoaderRepository.addClassLoader(_loader);
_view = new MBeanView(mbeanServer, _loader, "resin");
_globalView = new MBeanView(mbeanServer, _loader, "resin");
if (_loader != null
&& _loader != ClassLoader.getSystemClassLoader()) {
_parent = _mbeanServer.createContext(_loader.getParent());
if (_parent == this) {
_parent = null;
}
}
}
/**
* Returns the parent view.
*/
protected MBeanView getParentView()
{
return _mbeanServer.getParentView();
}
/**
* Returns the ClassLoaderRepository.
*/
public ClassLoaderRepository getClassLoaderRepository()
{
return _classLoaderRepository;
}
/**
* Returns the class loader.
*/
public ClassLoader getClassLoader()
{
return _loader;
}
/**
* Returns the view for this context.
*/
MBeanView getView()
{
return _view;
}
/**
* Returns the view for this context.
*/
MBeanView getGlobalView()
{
return _globalView;
}
/**
* Sets the properties.
*/
public void setProperties(Map props)
{
_properties.clear();
_properties.putAll(props);
}
/**
* Sets the properties.
*/
public LinkedHashMap copyProperties()
{
return new LinkedHashMap(_properties);
}
/**
* Returns the object name.
*/
public ObjectName getObjectName(String name)
throws MalformedObjectNameException
{
int len = name.length();
for (int i = 0; i < len; i++) {
char ch = name.charAt(i);
if (ch == ':')
return new ObjectName(name);
else if ('a' <= ch && ch <= 'z'
|| 'A' <= ch && ch <= 'Z'
|| '0' <= ch && ch <= '9'
|| ch == '-' || ch == '_' || ch == '.') {
continue;
}
else
break;
}
LinkedHashMap properties;
properties = new LinkedHashMap();
properties.putAll(_properties);
Jmx.parseProperties(properties, name);
return Jmx.getObjectName(_domain, properties);
}
/**
* Finds an admin object.
*/
MBeanWrapper getMBean(ObjectName name)
{
if (name != null)
return _mbeans.get(name);
else
return null;
}
/**
* Registers an MBean with the server.
*
* @param mbean the object to be registered as an MBean
* @param name the name of the mbean.
*
* @return the instantiated object.
*/
ObjectInstance registerMBean(MBeanWrapper mbean,
ObjectName name)
throws InstanceAlreadyExistsException,
MBeanRegistrationException,
NotCompliantMBeanException
{
if (mbean == null)
throw new NotCompliantMBeanException(L.l("{0} is a null mbean",
name));
if (_mbeans.get(name) != null)
throw new InstanceAlreadyExistsException(String.valueOf(name));
Object object = mbean.getObject();
MBeanRegistration registration = null;
if (object instanceof MBeanRegistration)
registration = (MBeanRegistration) object;
try {
if (registration != null)
name = registration.preRegister(_mbeanServer, name);
} catch (Exception e) {
throw new MBeanRegistrationException(e);
}
if (log.isLoggable(Level.FINEST)
&& ! name.equals(AbstractMBeanServer.SERVER_DELEGATE_NAME)) {
log.finest(getDebugName(name, mbean) + " registered in " + this);
}
addMBean(name, mbean);
/*
// server/21c4
if (_loader != Thread.currentThread().getContextClassLoader()) {
MBeanClose close = _mbeanClose.getLevel();
if (close == null) {
close = new MBeanClose();
_mbeanClose.set(close);
Environment.addCloseListener(close);
}
close.addName(name);
}
*/
try {
if (registration != null)
registration.postRegister(new Boolean(true));
} catch (Exception e) {
throw new MBeanRegistrationException(e);
}
if (_globalContext != null)
_globalContext.addMBean(name, mbean);
return mbean.getObjectInstance();
}
/**
* Unregisters an MBean from the server.
*
* @param name the name of the mbean.
*/
public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException,
MBeanRegistrationException
{
if (_mbeans == null) {
removeMBean(name);
return;
}
if (name.getDomain().equals("JMImplementation"))
return;
MBeanWrapper mbean = _mbeans.get(name);
if (mbean == null)
throw new InstanceNotFoundException(String.valueOf(name));
Object obj = mbean.getObject();
MBeanRegistration registration = null;
if (obj instanceof MBeanRegistration)
registration = (MBeanRegistration) obj;
try {
if (registration != null) {
try {
registration.preDeregister();
} catch (Throwable e) {
log.log(Level.WARNING, e.toString());
}
}
removeMBean(name);
if (registration != null) {
try {
registration.postDeregister();
} catch (Throwable e) {
log.log(Level.WARNING, e.toString());
}
}
} catch (Exception e) {
throw new MBeanRegistrationException(e);
}
}
/**
* Returns the MBean registered with the given name.
*
* @param name the name of the mbean.
*
* @return the matching mbean object.
*/
public ObjectInstance getObjectInstance(ObjectName name)
throws InstanceNotFoundException
{
MBeanWrapper mbean = getMBean(name);
if (mbean == null)
throw new InstanceNotFoundException(String.valueOf(name));
return mbean.getObjectInstance();
}
/**
* Returns true if the given object is registered with the server.
*
* @param name the name of the mbean to test.
*
* @return true if the object is registered.
*/
public boolean isRegistered(ObjectName name)
{
return _mbeans.get(name) != null;
}
/**
* Returns the number of MBeans registered.
*
* @return the number of registered mbeans.
*/
public int getMBeanCount()
{
return _mbeans.size();
}
/**
* Adds an object.
*/
private void addMBean(ObjectName name, MBeanWrapper mbean)
{
if (_mbeans == null)
throw new IllegalStateException(L.l("Adding MBean when context is closed"));
if (mbean == null) {
log.warning(L.l("'{0}' is an empty mbean", name));
return;
}
// at finest to avoid double logging for context and global
if (log.isLoggable(Level.FINEST))
log.finest(getDebugName(name, mbean) + " registered in " + this);
//log.fine(L.l("{0} registered in {1}", getDebugName(name, mbean), this));
_mbeans.put(name, mbean);
_view.add(name, mbean, true);
_globalView.add(name, mbean, true);
sendRegisterNotification(name);
for (MBeanContext parentContext = _parent;
parentContext != null;
parentContext = parentContext._parent) {
if (parentContext._globalView == null) {
log.finer("global view is empty");
}
else if (parentContext._globalView.add(name, mbean, false))
parentContext.sendRegisterNotification(name);
}
}
/**
* Removes an object.
*/
private MBeanWrapper removeMBean(ObjectName name)
{
MBeanWrapper mbean = null;
if (_mbeans != null)
mbean = _mbeans.remove(name);
if (_globalContext != null && _globalContext._mbeans != null)
_globalContext._mbeans.remove(name);
if (_view != null)
_view.remove(name);
if (_globalView != null && _globalView.remove(name) != null) {
try {
sendUnregisterNotification(name);
} catch (Throwable e) {
log.log(Level.WARNING, e.toString(), e);
}
}
if (_parent != null)
_parent.removeMBean(name);
return mbean;
}
/**
* Adds a listener to a registered MBean
*
* @param name the name of the mbean
* @param listener the listener object
* @param filter filters events the listener is interested in
* @param handback context to be returned to the listener
*/
void addNotificationListener(ObjectName name,
NotificationListener listener,
NotificationFilter filter,
Object handback)
{
synchronized (_listeners) {
_listeners.add(new Listener(name, listener, filter, handback));
}
}
/**
* Removes a listener to a registered MBean
*
* @param mbean the name of the mbean
* @param listener the listener object
*/
public void removeNotificationListener(ObjectName mbean,
NotificationListener listener)
{
synchronized (_listeners) {
for (int i = _listeners.size() - 1; i >= 0; i--) {
Listener oldListener = _listeners.get(i);
if (oldListener.match(mbean, listener))
_listeners.remove(i);
}
}
}
/**
* Removes a listener to a registered MBean
*
* @param mbean the name of the mbean
* @param listener the listener object
* @param filter filters events the listener is interested in
* @param handback context to be returned to the listener
*/
public void removeNotificationListener(ObjectName mbean,
NotificationListener listener,
NotificationFilter filter,
Object handback)
{
synchronized (_listeners) {
for (int i = _listeners.size() - 1; i >= 0; i--) {
Listener oldListener = _listeners.get(i);
if (oldListener.match(mbean, listener, filter, handback))
_listeners.remove(i);
}
}
}
/**
* Sends the register notification.
*/
void sendRegisterNotification(ObjectName name)
{
serverNotification(name,
MBeanServerNotification.REGISTRATION_NOTIFICATION);
}
/**
* Sends the register notification.
*/
void sendUnregisterNotification(ObjectName name)
{
serverNotification(name,
MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
}
/**
* Sends the notification
*/
private void serverNotification(ObjectName name, String type)
{
MBeanServerNotification notif;
ObjectName delegateName = AbstractMBeanServer.SERVER_DELEGATE_NAME;
notif = new MBeanServerNotification(type, delegateName, _seq++, name);
_delegate.sendNotification(notif);
}
/**
* Closes the context server.
*/
public void destroy()
{
try {
if (_mbeans == null)
return;
log.finest(this + " destroy");
ArrayList list = new ArrayList(_mbeans.keySet());
ArrayList listeners = new ArrayList(_listeners);
for (int i = 0; i < listeners.size(); i++) {
Listener listener = listeners.get(i);
try {
MBeanWrapper mbean = _globalView.getMBean(listener.getName());
if (mbean != null)
mbean.removeNotificationListener(listener.getListener(),
listener.getFilter(),
listener.getHandback());
} catch (Throwable e) {
log.log(Level.FINER, e.toString(), e);
}
}
for (int i = 0; i < list.size(); i++) {
ObjectName name = list.get(i);
try {
unregisterMBean(name);
} catch (Throwable e) {
log.log(Level.FINE, e.toString(), e);
}
}
_mbeanServer.removeContext(this, _loader);
} finally {
_parent = null;
_mbeanServer = null;
_globalContext = null;
_delegate = null;
_loader = null;
_classLoaderRepository = null;
_mbeans = null;
_listeners = null;
_view = null;
_globalView = null;
}
}
/**
* Returns the debug name for a registered mbean.
*
* @param name the name of the mbean
* @param mbean the mbean instance
* @return
*/
private String getDebugName(ObjectName name, MBeanWrapper mbean)
{
String className = mbean.getMBeanInfo().getClassName();
int p = className.lastIndexOf('.');
if (p > 0)
className = className.substring(p + 1);
return className + "[" + name + "]";
}
/**
* Display name.
*/
public String toString()
{
return getClass().getSimpleName() + "[" + _loader + "]";
}
/**
* Finalizer.
*/
/*
protected void finalize()
throws Throwable
{
super.finalize();
destroy();
}
*/
/**
* Listener references.
*/
static class Listener {
private ObjectName _name;
private WeakReference _listenerRef;
private WeakReference _filterRef;
private WeakReference