init
This commit is contained in:
164
java/org/apache/tomcat/util/modeler/AttributeInfo.java
Normal file
164
java/org/apache/tomcat/util/modeler/AttributeInfo.java
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Internal configuration information for an <code>Attribute</code>
|
||||
* descriptor.</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class AttributeInfo extends FeatureInfo {
|
||||
static final long serialVersionUID = -2511626862303972143L;
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
protected String displayName = null;
|
||||
|
||||
// Information about the method to use
|
||||
protected String getMethod = null;
|
||||
protected String setMethod = null;
|
||||
protected boolean readable = true;
|
||||
protected boolean writeable = true;
|
||||
protected boolean is = false;
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
/**
|
||||
* @return the display name of this attribute.
|
||||
*/
|
||||
public String getDisplayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the property getter method, if non-standard.
|
||||
*/
|
||||
public String getGetMethod() {
|
||||
if(getMethod == null)
|
||||
getMethod = getMethodName(getName(), true, isIs());
|
||||
return this.getMethod;
|
||||
}
|
||||
|
||||
public void setGetMethod(String getMethod) {
|
||||
this.getMethod = getMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a boolean attribute with an "is" getter?
|
||||
* @return <code>true</code> if this is a boolean attribute
|
||||
* with an "is" getter
|
||||
*/
|
||||
public boolean isIs() {
|
||||
return this.is;
|
||||
}
|
||||
|
||||
public void setIs(boolean is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is this attribute readable by management applications?
|
||||
* @return <code>true</code> if readable
|
||||
*/
|
||||
public boolean isReadable() {
|
||||
return this.readable;
|
||||
}
|
||||
|
||||
public void setReadable(boolean readable) {
|
||||
this.readable = readable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name of the property setter method, if non-standard.
|
||||
*/
|
||||
public String getSetMethod() {
|
||||
if( setMethod == null )
|
||||
setMethod = getMethodName(getName(), false, false);
|
||||
return this.setMethod;
|
||||
}
|
||||
|
||||
public void setSetMethod(String setMethod) {
|
||||
this.setMethod = setMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this attribute writable by management applications?
|
||||
* @return <code>true</code> if writable
|
||||
*/
|
||||
public boolean isWriteable() {
|
||||
return this.writeable;
|
||||
}
|
||||
|
||||
public void setWriteable(boolean writeable) {
|
||||
this.writeable = writeable;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Create and return a <code>ModelMBeanAttributeInfo</code> object that
|
||||
* corresponds to the attribute described by this instance.
|
||||
* @return the attribute info
|
||||
*/
|
||||
MBeanAttributeInfo createAttributeInfo() {
|
||||
// Return our cached information (if any)
|
||||
if (info == null) {
|
||||
info = new MBeanAttributeInfo(getName(), getType(), getDescription(),
|
||||
isReadable(), isWriteable(), false);
|
||||
}
|
||||
return (MBeanAttributeInfo)info;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------- Private Methods
|
||||
|
||||
|
||||
/**
|
||||
* Create and return the name of a default property getter or setter
|
||||
* method, according to the specified values.
|
||||
*
|
||||
* @param name Name of the property itself
|
||||
* @param getter Do we want a get method (versus a set method)?
|
||||
* @param is If returning a getter, do we want the "is" form?
|
||||
* @return the method name
|
||||
*/
|
||||
private String getMethodName(String name, boolean getter, boolean is) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (getter) {
|
||||
if (is)
|
||||
sb.append("is");
|
||||
else
|
||||
sb.append("get");
|
||||
} else
|
||||
sb.append("set");
|
||||
sb.append(Character.toUpperCase(name.charAt(0)));
|
||||
sb.append(name.substring(1));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
160
java/org/apache/tomcat/util/modeler/BaseAttributeFilter.java
Normal file
160
java/org/apache/tomcat/util/modeler/BaseAttributeFilter.java
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.management.AttributeChangeNotification;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationFilter;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Implementation of <code>NotificationFilter</code> for attribute change
|
||||
* notifications. This class is used by <code>BaseModelMBean</code> to
|
||||
* construct attribute change notification event filters when a filter is not
|
||||
* supplied by the application.</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class BaseAttributeFilter implements NotificationFilter {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// ----------------------------------------------------------- Constructors
|
||||
|
||||
/**
|
||||
* Construct a new filter that accepts only the specified attribute
|
||||
* name.
|
||||
*
|
||||
* @param name Name of the attribute to be accepted by this filter, or
|
||||
* <code>null</code> to accept all attribute names
|
||||
*/
|
||||
public BaseAttributeFilter(String name) {
|
||||
|
||||
super();
|
||||
if (name != null)
|
||||
addAttribute(name);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The set of attribute names that are accepted by this filter. If this
|
||||
* list is empty, all attribute names are accepted.
|
||||
*/
|
||||
private HashSet<String> names = new HashSet<>();
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Add a new attribute name to the set of names accepted by this filter.
|
||||
*
|
||||
* @param name Name of the attribute to be accepted
|
||||
*/
|
||||
public void addAttribute(String name) {
|
||||
|
||||
synchronized (names) {
|
||||
names.add(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear all accepted names from this filter, so that it will accept
|
||||
* all attribute names.
|
||||
*/
|
||||
public void clear() {
|
||||
|
||||
synchronized (names) {
|
||||
names.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the set of names that are accepted by this filter. If this
|
||||
* filter accepts all attribute names, a zero length array will be
|
||||
* returned.
|
||||
* @return the array of names
|
||||
*/
|
||||
public String[] getNames() {
|
||||
|
||||
synchronized (names) {
|
||||
return names.toArray(new String[names.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Test whether notification enabled for this event.
|
||||
* Return true if:</p>
|
||||
* <ul>
|
||||
* <li>This is an attribute change notification</li>
|
||||
* <li>Either the set of accepted names is empty (implying that all
|
||||
* attribute names are of interest) or the set of accepted names
|
||||
* includes the name of the attribute in this notification</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
public boolean isNotificationEnabled(Notification notification) {
|
||||
|
||||
if (notification == null)
|
||||
return false;
|
||||
if (!(notification instanceof AttributeChangeNotification))
|
||||
return false;
|
||||
AttributeChangeNotification acn =
|
||||
(AttributeChangeNotification) notification;
|
||||
if (!AttributeChangeNotification.ATTRIBUTE_CHANGE.equals(acn.getType()))
|
||||
return false;
|
||||
synchronized (names) {
|
||||
if (names.size() < 1)
|
||||
return true;
|
||||
else
|
||||
return names.contains(acn.getAttributeName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove an attribute name from the set of names accepted by this
|
||||
* filter.
|
||||
*
|
||||
* @param name Name of the attribute to be removed
|
||||
*/
|
||||
public void removeAttribute(String name) {
|
||||
|
||||
synchronized (names) {
|
||||
names.remove(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
915
java/org/apache/tomcat/util/modeler/BaseModelMBean.java
Normal file
915
java/org/apache/tomcat/util/modeler/BaseModelMBean.java
Normal file
@@ -0,0 +1,915 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeChangeNotification;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanRegistration;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.RuntimeErrorException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import javax.management.modelmbean.InvalidTargetObjectTypeException;
|
||||
import javax.management.modelmbean.ModelMBeanNotificationBroadcaster;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/*
|
||||
* Changes from commons.modeler:
|
||||
*
|
||||
* - use DynamicMBean
|
||||
* - remove methods not used in tomcat and redundant/not very generic
|
||||
* - must be created from the ManagedBean - I don't think there were any direct
|
||||
* uses, but now it is required.
|
||||
* - some of the gratuitous flexibility removed - instead this is more predictive and
|
||||
* strict with the use cases.
|
||||
* - all Method and metadata is stored in ManagedBean. BaseModelBMean and ManagedBean act
|
||||
* like Object and Class.
|
||||
* - setModelMBean is no longer called on resources ( not used in tomcat )
|
||||
* - no caching of Methods for now - operations and setters are not called repeatedly in most
|
||||
* management use cases. Getters shouldn't be called very frequently either - and even if they
|
||||
* are, the overhead of getting the method should be small compared with other JMX costs ( RMI, etc ).
|
||||
* We can add getter cache if needed.
|
||||
* - removed unused constructor, fields
|
||||
*
|
||||
* TODO:
|
||||
* - clean up catalina.mbeans, stop using weird inheritance
|
||||
*/
|
||||
|
||||
/**
|
||||
* <p>Basic implementation of the <code>DynamicMBean</code> interface, which
|
||||
* supports the minimal requirements of the interface contract.</p>
|
||||
*
|
||||
* <p>This can be used directly to wrap an existing java bean, or inside
|
||||
* an mlet or anywhere an MBean would be used.
|
||||
*
|
||||
* Limitations:
|
||||
* <ul>
|
||||
* <li>Only managed resources of type <code>objectReference</code> are
|
||||
* supported.</li>
|
||||
* <li>Caching of attribute values and operation results is not supported.
|
||||
* All calls to <code>invoke()</code> are immediately executed.</li>
|
||||
* <li>Persistence of MBean attributes and operations is not supported.</li>
|
||||
* <li>All classes referenced as attribute types, operation parameters, or
|
||||
* operation return values must be one of the following:
|
||||
* <ul>
|
||||
* <li>One of the Java primitive types (boolean, byte, char, double,
|
||||
* float, integer, long, short). Corresponding value will be wrapped
|
||||
* in the appropriate wrapper class automatically.</li>
|
||||
* <li>Operations that return no value should declare a return type of
|
||||
* <code>void</code>.</li>
|
||||
* </ul>
|
||||
* <li>Attribute caching is not supported</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Costin Manolache
|
||||
*/
|
||||
public class BaseModelMBean implements DynamicMBean, MBeanRegistration,
|
||||
ModelMBeanNotificationBroadcaster {
|
||||
|
||||
private static final Log log = LogFactory.getLog(BaseModelMBean.class);
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
protected ObjectName oname=null;
|
||||
|
||||
/**
|
||||
* Notification broadcaster for attribute changes.
|
||||
*/
|
||||
protected BaseNotificationBroadcaster attributeBroadcaster = null;
|
||||
|
||||
/**
|
||||
* Notification broadcaster for general notifications.
|
||||
*/
|
||||
protected BaseNotificationBroadcaster generalBroadcaster = null;
|
||||
|
||||
/** Metadata for the mbean instance.
|
||||
*/
|
||||
protected ManagedBean managedBean = null;
|
||||
|
||||
/**
|
||||
* The managed resource this MBean is associated with (if any).
|
||||
*/
|
||||
protected Object resource = null;
|
||||
|
||||
// --------------------------------------------------- DynamicMBean Methods
|
||||
// TODO: move to ManagedBean
|
||||
static final Object[] NO_ARGS_PARAM = new Object[0];
|
||||
|
||||
protected String resourceType = null;
|
||||
|
||||
// key: operation val: invoke method
|
||||
//private Hashtable invokeAttMap=new Hashtable();
|
||||
|
||||
/**
|
||||
* Obtain and return the value of a specific attribute of this MBean.
|
||||
*
|
||||
* @param name Name of the requested attribute
|
||||
*
|
||||
* @exception AttributeNotFoundException if this attribute is not
|
||||
* supported by this MBean
|
||||
* @exception MBeanException if the initializer of an object
|
||||
* throws an exception
|
||||
* @exception ReflectionException if a Java reflection exception
|
||||
* occurs when invoking the getter
|
||||
*/
|
||||
@Override
|
||||
public Object getAttribute(String name)
|
||||
throws AttributeNotFoundException, MBeanException,
|
||||
ReflectionException {
|
||||
// Validate the input parameters
|
||||
if (name == null)
|
||||
throw new RuntimeOperationsException
|
||||
(new IllegalArgumentException("Attribute name is null"),
|
||||
"Attribute name is null");
|
||||
|
||||
if( (resource instanceof DynamicMBean) &&
|
||||
! ( resource instanceof BaseModelMBean )) {
|
||||
return ((DynamicMBean)resource).getAttribute(name);
|
||||
}
|
||||
|
||||
Method m=managedBean.getGetter(name, this, resource);
|
||||
Object result = null;
|
||||
try {
|
||||
Class<?> declaring = m.getDeclaringClass();
|
||||
// workaround for catalina weird mbeans - the declaring class is BaseModelMBean.
|
||||
// but this is the catalina class.
|
||||
if( declaring.isAssignableFrom(this.getClass()) ) {
|
||||
result = m.invoke(this, NO_ARGS_PARAM );
|
||||
} else {
|
||||
result = m.invoke(resource, NO_ARGS_PARAM );
|
||||
}
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable t = e.getTargetException();
|
||||
if (t == null)
|
||||
t = e;
|
||||
if (t instanceof RuntimeException)
|
||||
throw new RuntimeOperationsException
|
||||
((RuntimeException) t, "Exception invoking method " + name);
|
||||
else if (t instanceof Error)
|
||||
throw new RuntimeErrorException
|
||||
((Error) t, "Error invoking method " + name);
|
||||
else
|
||||
throw new MBeanException
|
||||
(e, "Exception invoking method " + name);
|
||||
} catch (Exception e) {
|
||||
throw new MBeanException
|
||||
(e, "Exception invoking method " + name);
|
||||
}
|
||||
|
||||
// Return the results of this method invocation
|
||||
// FIXME - should we validate the return type?
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain and return the values of several attributes of this MBean.
|
||||
*
|
||||
* @param names Names of the requested attributes
|
||||
*/
|
||||
@Override
|
||||
public AttributeList getAttributes(String names[]) {
|
||||
|
||||
// Validate the input parameters
|
||||
if (names == null)
|
||||
throw new RuntimeOperationsException
|
||||
(new IllegalArgumentException("Attribute names list is null"),
|
||||
"Attribute names list is null");
|
||||
|
||||
// Prepare our response, eating all exceptions
|
||||
AttributeList response = new AttributeList();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
try {
|
||||
response.add(new Attribute(names[i],getAttribute(names[i])));
|
||||
} catch (Exception e) {
|
||||
// Not having a particular attribute in the response
|
||||
// is the indication of a getter problem
|
||||
}
|
||||
}
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
public void setManagedBean(ManagedBean managedBean) {
|
||||
this.managedBean = managedBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the <code>MBeanInfo</code> object for this MBean.
|
||||
*/
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo() {
|
||||
return managedBean.getMBeanInfo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoke a particular method on this MBean, and return any returned
|
||||
* value.
|
||||
*
|
||||
* <p><strong>IMPLEMENTATION NOTE</strong> - This implementation will
|
||||
* attempt to invoke this method on the MBean itself, or (if not
|
||||
* available) on the managed resource object associated with this
|
||||
* MBean.</p>
|
||||
*
|
||||
* @param name Name of the operation to be invoked
|
||||
* @param params Array containing the method parameters of this operation
|
||||
* @param signature Array containing the class names representing
|
||||
* the signature of this operation
|
||||
*
|
||||
* @exception MBeanException if the initializer of an object
|
||||
* throws an exception
|
||||
* @exception ReflectionException if a Java reflection exception
|
||||
* occurs when invoking a method
|
||||
*/
|
||||
@Override
|
||||
public Object invoke(String name, Object params[], String signature[])
|
||||
throws MBeanException, ReflectionException
|
||||
{
|
||||
if( (resource instanceof DynamicMBean) &&
|
||||
! ( resource instanceof BaseModelMBean )) {
|
||||
return ((DynamicMBean)resource).invoke(name, params, signature);
|
||||
}
|
||||
|
||||
// Validate the input parameters
|
||||
if (name == null)
|
||||
throw new RuntimeOperationsException
|
||||
(new IllegalArgumentException("Method name is null"),
|
||||
"Method name is null");
|
||||
|
||||
if( log.isDebugEnabled()) log.debug("Invoke " + name);
|
||||
|
||||
Method method= managedBean.getInvoke(name, params, signature, this, resource);
|
||||
|
||||
// Invoke the selected method on the appropriate object
|
||||
Object result = null;
|
||||
try {
|
||||
if( method.getDeclaringClass().isAssignableFrom( this.getClass()) ) {
|
||||
result = method.invoke(this, params );
|
||||
} else {
|
||||
result = method.invoke(resource, params);
|
||||
}
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable t = e.getTargetException();
|
||||
log.error("Exception invoking method " + name , t );
|
||||
if (t == null)
|
||||
t = e;
|
||||
if (t instanceof RuntimeException)
|
||||
throw new RuntimeOperationsException
|
||||
((RuntimeException) t, "Exception invoking method " + name);
|
||||
else if (t instanceof Error)
|
||||
throw new RuntimeErrorException
|
||||
((Error) t, "Error invoking method " + name);
|
||||
else
|
||||
throw new MBeanException
|
||||
((Exception)t, "Exception invoking method " + name);
|
||||
} catch (Exception e) {
|
||||
log.error("Exception invoking method " + name , e );
|
||||
throw new MBeanException
|
||||
(e, "Exception invoking method " + name);
|
||||
}
|
||||
|
||||
// Return the results of this method invocation
|
||||
// FIXME - should we validate the return type?
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
static Class<?> getAttributeClass(String signature)
|
||||
throws ReflectionException
|
||||
{
|
||||
if (signature.equals(Boolean.TYPE.getName()))
|
||||
return Boolean.TYPE;
|
||||
else if (signature.equals(Byte.TYPE.getName()))
|
||||
return Byte.TYPE;
|
||||
else if (signature.equals(Character.TYPE.getName()))
|
||||
return Character.TYPE;
|
||||
else if (signature.equals(Double.TYPE.getName()))
|
||||
return Double.TYPE;
|
||||
else if (signature.equals(Float.TYPE.getName()))
|
||||
return Float.TYPE;
|
||||
else if (signature.equals(Integer.TYPE.getName()))
|
||||
return Integer.TYPE;
|
||||
else if (signature.equals(Long.TYPE.getName()))
|
||||
return Long.TYPE;
|
||||
else if (signature.equals(Short.TYPE.getName()))
|
||||
return Short.TYPE;
|
||||
else {
|
||||
try {
|
||||
ClassLoader cl=Thread.currentThread().getContextClassLoader();
|
||||
if( cl!=null )
|
||||
return cl.loadClass(signature);
|
||||
} catch( ClassNotFoundException e ) {
|
||||
}
|
||||
try {
|
||||
return Class.forName(signature);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ReflectionException
|
||||
(e, "Cannot find Class for " + signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a specific attribute of this MBean.
|
||||
*
|
||||
* @param attribute The identification of the attribute to be set
|
||||
* and the new value
|
||||
*
|
||||
* @exception AttributeNotFoundException if this attribute is not
|
||||
* supported by this MBean
|
||||
* @exception MBeanException if the initializer of an object
|
||||
* throws an exception
|
||||
* @exception ReflectionException if a Java reflection exception
|
||||
* occurs when invoking the getter
|
||||
*/
|
||||
@Override
|
||||
public void setAttribute(Attribute attribute)
|
||||
throws AttributeNotFoundException, MBeanException,
|
||||
ReflectionException
|
||||
{
|
||||
if( log.isDebugEnabled() )
|
||||
log.debug("Setting attribute " + this + " " + attribute );
|
||||
|
||||
if( (resource instanceof DynamicMBean) &&
|
||||
! ( resource instanceof BaseModelMBean )) {
|
||||
try {
|
||||
((DynamicMBean)resource).setAttribute(attribute);
|
||||
} catch (InvalidAttributeValueException e) {
|
||||
throw new MBeanException(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate the input parameters
|
||||
if (attribute == null)
|
||||
throw new RuntimeOperationsException
|
||||
(new IllegalArgumentException("Attribute is null"),
|
||||
"Attribute is null");
|
||||
|
||||
String name = attribute.getName();
|
||||
Object value = attribute.getValue();
|
||||
|
||||
if (name == null)
|
||||
throw new RuntimeOperationsException
|
||||
(new IllegalArgumentException("Attribute name is null"),
|
||||
"Attribute name is null");
|
||||
|
||||
Object oldValue=null;
|
||||
//if( getAttMap.get(name) != null )
|
||||
// oldValue=getAttribute( name );
|
||||
|
||||
Method m=managedBean.getSetter(name,this,resource);
|
||||
|
||||
try {
|
||||
if( m.getDeclaringClass().isAssignableFrom( this.getClass()) ) {
|
||||
m.invoke(this, new Object[] { value });
|
||||
} else {
|
||||
m.invoke(resource, new Object[] { value });
|
||||
}
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable t = e.getTargetException();
|
||||
if (t == null)
|
||||
t = e;
|
||||
if (t instanceof RuntimeException)
|
||||
throw new RuntimeOperationsException
|
||||
((RuntimeException) t, "Exception invoking method " + name);
|
||||
else if (t instanceof Error)
|
||||
throw new RuntimeErrorException
|
||||
((Error) t, "Error invoking method " + name);
|
||||
else
|
||||
throw new MBeanException
|
||||
(e, "Exception invoking method " + name);
|
||||
} catch (Exception e) {
|
||||
log.error("Exception invoking method " + name , e );
|
||||
throw new MBeanException
|
||||
(e, "Exception invoking method " + name);
|
||||
}
|
||||
try {
|
||||
sendAttributeChangeNotification(new Attribute( name, oldValue),
|
||||
attribute);
|
||||
} catch(Exception ex) {
|
||||
log.error("Error sending notification " + name, ex);
|
||||
}
|
||||
//attributes.put( name, value );
|
||||
// if( source != null ) {
|
||||
// // this mbean is associated with a source - maybe we want to persist
|
||||
// source.updateField(oname, name, value);
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if( resource==null )
|
||||
return "BaseModelMbean[" + resourceType + "]";
|
||||
return resource.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the values of several attributes of this MBean.
|
||||
*
|
||||
* @param attributes THe names and values to be set
|
||||
*
|
||||
* @return The list of attributes that were set and their new values
|
||||
*/
|
||||
@Override
|
||||
public AttributeList setAttributes(AttributeList attributes) {
|
||||
AttributeList response = new AttributeList();
|
||||
|
||||
// Validate the input parameters
|
||||
if (attributes == null)
|
||||
return response;
|
||||
|
||||
// Prepare and return our response, eating all exceptions
|
||||
String names[] = new String[attributes.size()];
|
||||
int n = 0;
|
||||
Iterator<?> items = attributes.iterator();
|
||||
while (items.hasNext()) {
|
||||
Attribute item = (Attribute) items.next();
|
||||
names[n++] = item.getName();
|
||||
try {
|
||||
setAttribute(item);
|
||||
} catch (Exception e) {
|
||||
// Ignore all exceptions
|
||||
}
|
||||
}
|
||||
|
||||
return getAttributes(names);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------- ModelMBean Methods
|
||||
|
||||
|
||||
/**
|
||||
* Get the instance handle of the object against which we execute
|
||||
* all methods in this ModelMBean management interface.
|
||||
*
|
||||
* @return the backend managed object
|
||||
* @exception InstanceNotFoundException if the managed resource object
|
||||
* cannot be found
|
||||
* @exception InvalidTargetObjectTypeException if the managed resource
|
||||
* object is of the wrong type
|
||||
* @exception MBeanException if the initializer of the object throws
|
||||
* an exception
|
||||
* @exception RuntimeOperationsException if the managed resource or the
|
||||
* resource type is <code>null</code> or invalid
|
||||
*/
|
||||
public Object getManagedResource()
|
||||
throws InstanceNotFoundException, InvalidTargetObjectTypeException,
|
||||
MBeanException, RuntimeOperationsException {
|
||||
|
||||
if (resource == null)
|
||||
throw new RuntimeOperationsException
|
||||
(new IllegalArgumentException("Managed resource is null"),
|
||||
"Managed resource is null");
|
||||
|
||||
return resource;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the instance handle of the object against which we will execute
|
||||
* all methods in this ModelMBean management interface.
|
||||
*
|
||||
* The caller can provide the mbean instance or the object name to
|
||||
* the resource, if needed.
|
||||
*
|
||||
* @param resource The resource object to be managed
|
||||
* @param type The type of reference for the managed resource
|
||||
* ("ObjectReference", "Handle", "IOR", "EJBHandle", or
|
||||
* "RMIReference")
|
||||
*
|
||||
* @exception InstanceNotFoundException if the managed resource object
|
||||
* cannot be found
|
||||
* @exception MBeanException if the initializer of the object throws
|
||||
* an exception
|
||||
* @exception RuntimeOperationsException if the managed resource or the
|
||||
* resource type is <code>null</code> or invalid
|
||||
*/
|
||||
public void setManagedResource(Object resource, String type)
|
||||
throws InstanceNotFoundException,
|
||||
MBeanException, RuntimeOperationsException
|
||||
{
|
||||
if (resource == null)
|
||||
throw new RuntimeOperationsException
|
||||
(new IllegalArgumentException("Managed resource is null"),
|
||||
"Managed resource is null");
|
||||
|
||||
// if (!"objectreference".equalsIgnoreCase(type))
|
||||
// throw new InvalidTargetObjectTypeException(type);
|
||||
|
||||
this.resource = resource;
|
||||
this.resourceType = resource.getClass().getName();
|
||||
|
||||
// // Make the resource aware of the model mbean.
|
||||
// try {
|
||||
// Method m=resource.getClass().getMethod("setModelMBean",
|
||||
// new Class[] {ModelMBean.class});
|
||||
// if( m!= null ) {
|
||||
// m.invoke(resource, new Object[] {this});
|
||||
// }
|
||||
// } catch( NoSuchMethodException t ) {
|
||||
// // ignore
|
||||
// } catch( Throwable t ) {
|
||||
// log.error( "Can't set model mbean ", t );
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------ ModelMBeanNotificationBroadcaster Methods
|
||||
|
||||
|
||||
/**
|
||||
* Add an attribute change notification event listener to this MBean.
|
||||
*
|
||||
* @param listener Listener that will receive event notifications
|
||||
* @param name Name of the attribute of interest, or <code>null</code>
|
||||
* to indicate interest in all attributes
|
||||
* @param handback Handback object to be sent along with event
|
||||
* notifications
|
||||
*
|
||||
* @exception IllegalArgumentException if the listener parameter is null
|
||||
*/
|
||||
@Override
|
||||
public void addAttributeChangeNotificationListener
|
||||
(NotificationListener listener, String name, Object handback)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
if (listener == null)
|
||||
throw new IllegalArgumentException("Listener is null");
|
||||
if (attributeBroadcaster == null)
|
||||
attributeBroadcaster = new BaseNotificationBroadcaster();
|
||||
|
||||
if( log.isDebugEnabled() )
|
||||
log.debug("addAttributeNotificationListener " + listener);
|
||||
|
||||
BaseAttributeFilter filter = new BaseAttributeFilter(name);
|
||||
attributeBroadcaster.addNotificationListener
|
||||
(listener, filter, handback);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove an attribute change notification event listener from
|
||||
* this MBean.
|
||||
*
|
||||
* @param listener The listener to be removed
|
||||
* @param name The attribute name for which no more events are required
|
||||
*
|
||||
*
|
||||
* @exception ListenerNotFoundException if this listener is not
|
||||
* registered in the MBean
|
||||
*/
|
||||
@Override
|
||||
public void removeAttributeChangeNotificationListener
|
||||
(NotificationListener listener, String name)
|
||||
throws ListenerNotFoundException {
|
||||
|
||||
if (listener == null)
|
||||
throw new IllegalArgumentException("Listener is null");
|
||||
|
||||
// FIXME - currently this removes *all* notifications for this listener
|
||||
if (attributeBroadcaster != null) {
|
||||
attributeBroadcaster.removeNotificationListener(listener);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send an <code>AttributeChangeNotification</code> to all registered
|
||||
* listeners.
|
||||
*
|
||||
* @param notification The <code>AttributeChangeNotification</code>
|
||||
* that will be passed
|
||||
*
|
||||
* @exception MBeanException if an object initializer throws an
|
||||
* exception
|
||||
* @exception RuntimeOperationsException wraps IllegalArgumentException
|
||||
* when the specified notification is <code>null</code> or invalid
|
||||
*/
|
||||
@Override
|
||||
public void sendAttributeChangeNotification
|
||||
(AttributeChangeNotification notification)
|
||||
throws MBeanException, RuntimeOperationsException {
|
||||
|
||||
if (notification == null)
|
||||
throw new RuntimeOperationsException
|
||||
(new IllegalArgumentException("Notification is null"),
|
||||
"Notification is null");
|
||||
if (attributeBroadcaster == null)
|
||||
return; // This means there are no registered listeners
|
||||
if( log.isDebugEnabled() )
|
||||
log.debug( "AttributeChangeNotification " + notification );
|
||||
attributeBroadcaster.sendNotification(notification);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send an <code>AttributeChangeNotification</code> to all registered
|
||||
* listeners.
|
||||
*
|
||||
* @param oldValue The original value of the <code>Attribute</code>
|
||||
* @param newValue The new value of the <code>Attribute</code>
|
||||
*
|
||||
* @exception MBeanException if an object initializer throws an
|
||||
* exception
|
||||
* @exception RuntimeOperationsException wraps IllegalArgumentException
|
||||
* when the specified notification is <code>null</code> or invalid
|
||||
*/
|
||||
@Override
|
||||
public void sendAttributeChangeNotification
|
||||
(Attribute oldValue, Attribute newValue)
|
||||
throws MBeanException, RuntimeOperationsException {
|
||||
|
||||
// Calculate the class name for the change notification
|
||||
String type = null;
|
||||
if (newValue.getValue() != null)
|
||||
type = newValue.getValue().getClass().getName();
|
||||
else if (oldValue.getValue() != null)
|
||||
type = oldValue.getValue().getClass().getName();
|
||||
else
|
||||
return; // Old and new are both null == no change
|
||||
|
||||
AttributeChangeNotification notification =
|
||||
new AttributeChangeNotification
|
||||
(this, 1, System.currentTimeMillis(),
|
||||
"Attribute value has changed",
|
||||
oldValue.getName(), type,
|
||||
oldValue.getValue(), newValue.getValue());
|
||||
sendAttributeChangeNotification(notification);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a <code>Notification</code> to all registered listeners as a
|
||||
* <code>jmx.modelmbean.general</code> notification.
|
||||
*
|
||||
* @param notification The <code>Notification</code> that will be passed
|
||||
*
|
||||
* @exception MBeanException if an object initializer throws an
|
||||
* exception
|
||||
* @exception RuntimeOperationsException wraps IllegalArgumentException
|
||||
* when the specified notification is <code>null</code> or invalid
|
||||
*/
|
||||
@Override
|
||||
public void sendNotification(Notification notification)
|
||||
throws MBeanException, RuntimeOperationsException {
|
||||
|
||||
if (notification == null)
|
||||
throw new RuntimeOperationsException
|
||||
(new IllegalArgumentException("Notification is null"),
|
||||
"Notification is null");
|
||||
if (generalBroadcaster == null)
|
||||
return; // This means there are no registered listeners
|
||||
generalBroadcaster.sendNotification(notification);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a <code>Notification</code> which contains the specified string
|
||||
* as a <code>jmx.modelmbean.generic</code> notification.
|
||||
*
|
||||
* @param message The message string to be passed
|
||||
*
|
||||
* @exception MBeanException if an object initializer throws an
|
||||
* exception
|
||||
* @exception RuntimeOperationsException wraps IllegalArgumentException
|
||||
* when the specified notification is <code>null</code> or invalid
|
||||
*/
|
||||
@Override
|
||||
public void sendNotification(String message)
|
||||
throws MBeanException, RuntimeOperationsException {
|
||||
|
||||
if (message == null)
|
||||
throw new RuntimeOperationsException
|
||||
(new IllegalArgumentException("Message is null"),
|
||||
"Message is null");
|
||||
Notification notification = new Notification
|
||||
("jmx.modelmbean.generic", this, 1, message);
|
||||
sendNotification(notification);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------- NotificationBroadcaster Methods
|
||||
|
||||
|
||||
/**
|
||||
* Add a notification event listener to this MBean.
|
||||
*
|
||||
* @param listener Listener that will receive event notifications
|
||||
* @param filter Filter object used to filter event notifications
|
||||
* actually delivered, or <code>null</code> for no filtering
|
||||
* @param handback Handback object to be sent along with event
|
||||
* notifications
|
||||
*
|
||||
* @exception IllegalArgumentException if the listener parameter is null
|
||||
*/
|
||||
@Override
|
||||
public void addNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
if (listener == null)
|
||||
throw new IllegalArgumentException("Listener is null");
|
||||
|
||||
if( log.isDebugEnabled() ) log.debug("addNotificationListener " + listener);
|
||||
|
||||
if (generalBroadcaster == null)
|
||||
generalBroadcaster = new BaseNotificationBroadcaster();
|
||||
generalBroadcaster.addNotificationListener
|
||||
(listener, filter, handback);
|
||||
|
||||
// We'll send the attribute change notifications to all listeners ( who care )
|
||||
// The normal filtering can be used.
|
||||
// The problem is that there is no other way to add attribute change listeners
|
||||
// to a model mbean ( AFAIK ). I suppose the spec should be fixed.
|
||||
if (attributeBroadcaster == null)
|
||||
attributeBroadcaster = new BaseNotificationBroadcaster();
|
||||
|
||||
if( log.isDebugEnabled() )
|
||||
log.debug("addAttributeNotificationListener " + listener);
|
||||
|
||||
attributeBroadcaster.addNotificationListener
|
||||
(listener, filter, handback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return an <code>MBeanNotificationInfo</code> object describing the
|
||||
* notifications sent by this MBean.
|
||||
*/
|
||||
@Override
|
||||
public MBeanNotificationInfo[] getNotificationInfo() {
|
||||
|
||||
// Acquire the set of application notifications
|
||||
MBeanNotificationInfo current[] = getMBeanInfo().getNotifications();
|
||||
MBeanNotificationInfo response[] =
|
||||
new MBeanNotificationInfo[current.length + 2];
|
||||
// Descriptor descriptor = null;
|
||||
|
||||
// Fill in entry for general notifications
|
||||
// descriptor = new DescriptorSupport
|
||||
// (new String[] { "name=GENERIC",
|
||||
// "descriptorType=notification",
|
||||
// "log=T",
|
||||
// "severity=5",
|
||||
// "displayName=jmx.modelmbean.generic" });
|
||||
response[0] = new MBeanNotificationInfo
|
||||
(new String[] { "jmx.modelmbean.generic" },
|
||||
"GENERIC",
|
||||
"Text message notification from the managed resource");
|
||||
//descriptor);
|
||||
|
||||
// Fill in entry for attribute change notifications
|
||||
// descriptor = new DescriptorSupport
|
||||
// (new String[] { "name=ATTRIBUTE_CHANGE",
|
||||
// "descriptorType=notification",
|
||||
// "log=T",
|
||||
// "severity=5",
|
||||
// "displayName=jmx.attribute.change" });
|
||||
response[1] = new MBeanNotificationInfo
|
||||
(new String[] { "jmx.attribute.change" },
|
||||
"ATTRIBUTE_CHANGE",
|
||||
"Observed MBean attribute value has changed");
|
||||
//descriptor);
|
||||
|
||||
// Copy remaining notifications as reported by the application
|
||||
System.arraycopy(current, 0, response, 2, current.length);
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a notification event listener from this MBean.
|
||||
*
|
||||
* @param listener The listener to be removed (any and all registrations
|
||||
* for this listener will be eliminated)
|
||||
*
|
||||
* @exception ListenerNotFoundException if this listener is not
|
||||
* registered in the MBean
|
||||
*/
|
||||
@Override
|
||||
public void removeNotificationListener(NotificationListener listener)
|
||||
throws ListenerNotFoundException {
|
||||
|
||||
if (listener == null)
|
||||
throw new IllegalArgumentException("Listener is null");
|
||||
|
||||
if (generalBroadcaster != null) {
|
||||
generalBroadcaster.removeNotificationListener(listener);
|
||||
}
|
||||
|
||||
if (attributeBroadcaster != null) {
|
||||
attributeBroadcaster.removeNotificationListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getModelerType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return getModelerType();
|
||||
}
|
||||
|
||||
public ObjectName getJmxName() {
|
||||
return oname;
|
||||
}
|
||||
|
||||
public String getObjectName() {
|
||||
if (oname != null) {
|
||||
return oname.toString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------- Registration --------------------
|
||||
// XXX We can add some method patterns here- like setName() and
|
||||
// setDomain() for code that doesn't implement the Registration
|
||||
|
||||
@Override
|
||||
public ObjectName preRegister(MBeanServer server,
|
||||
ObjectName name)
|
||||
throws Exception
|
||||
{
|
||||
if( log.isDebugEnabled())
|
||||
log.debug("preRegister " + resource + " " + name );
|
||||
oname=name;
|
||||
if( resource instanceof MBeanRegistration ) {
|
||||
oname = ((MBeanRegistration)resource).preRegister(server, name );
|
||||
}
|
||||
return oname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postRegister(Boolean registrationDone) {
|
||||
if( resource instanceof MBeanRegistration ) {
|
||||
((MBeanRegistration)resource).postRegister(registrationDone);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDeregister() throws Exception {
|
||||
if( resource instanceof MBeanRegistration ) {
|
||||
((MBeanRegistration)resource).preDeregister();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDeregister() {
|
||||
if( resource instanceof MBeanRegistration ) {
|
||||
((MBeanRegistration)resource).postDeregister();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationBroadcaster;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Implementation of <code>NotificationBroadcaster</code> for attribute
|
||||
* change notifications. This class is used by <code>BaseModelMBean</code> to
|
||||
* handle notifications of attribute change events to interested listeners.
|
||||
*</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Costin Manolache
|
||||
*/
|
||||
|
||||
public class BaseNotificationBroadcaster implements NotificationBroadcaster {
|
||||
|
||||
|
||||
// ----------------------------------------------------------- Constructors
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The set of registered <code>BaseNotificationBroadcasterEntry</code>
|
||||
* entries.
|
||||
*/
|
||||
protected ArrayList<BaseNotificationBroadcasterEntry> entries =
|
||||
new ArrayList<>();
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Add a notification event listener to this MBean.
|
||||
*
|
||||
* @param listener Listener that will receive event notifications
|
||||
* @param filter Filter object used to filter event notifications
|
||||
* actually delivered, or <code>null</code> for no filtering
|
||||
* @param handback Handback object to be sent along with event
|
||||
* notifications
|
||||
*
|
||||
* @exception IllegalArgumentException if the listener parameter is null
|
||||
*/
|
||||
@Override
|
||||
public void addNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
synchronized (entries) {
|
||||
|
||||
// Optimization to coalesce attribute name filters
|
||||
if (filter instanceof BaseAttributeFilter) {
|
||||
BaseAttributeFilter newFilter = (BaseAttributeFilter) filter;
|
||||
for (BaseNotificationBroadcasterEntry item : entries) {
|
||||
if ((item.listener == listener) &&
|
||||
(item.filter != null) &&
|
||||
(item.filter instanceof BaseAttributeFilter) &&
|
||||
(item.handback == handback)) {
|
||||
BaseAttributeFilter oldFilter =
|
||||
(BaseAttributeFilter) item.filter;
|
||||
String newNames[] = newFilter.getNames();
|
||||
String oldNames[] = oldFilter.getNames();
|
||||
if (newNames.length == 0) {
|
||||
oldFilter.clear();
|
||||
} else {
|
||||
if (oldNames.length != 0) {
|
||||
for (int i = 0; i < newNames.length; i++)
|
||||
oldFilter.addAttribute(newNames[i]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// General purpose addition of a new entry
|
||||
entries.add(new BaseNotificationBroadcasterEntry
|
||||
(listener, filter, handback));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return an <code>MBeanNotificationInfo</code> object describing the
|
||||
* notifications sent by this MBean.
|
||||
*/
|
||||
@Override
|
||||
public MBeanNotificationInfo[] getNotificationInfo() {
|
||||
return new MBeanNotificationInfo[0];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a notification event listener from this MBean.
|
||||
*
|
||||
* @param listener The listener to be removed (any and all registrations
|
||||
* for this listener will be eliminated)
|
||||
*
|
||||
* @exception ListenerNotFoundException if this listener is not
|
||||
* registered in the MBean
|
||||
*/
|
||||
@Override
|
||||
public void removeNotificationListener(NotificationListener listener)
|
||||
throws ListenerNotFoundException {
|
||||
|
||||
synchronized (entries) {
|
||||
Iterator<BaseNotificationBroadcasterEntry> items =
|
||||
entries.iterator();
|
||||
while (items.hasNext()) {
|
||||
BaseNotificationBroadcasterEntry item = items.next();
|
||||
if (item.listener == listener)
|
||||
items.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send the specified notification to all interested listeners.
|
||||
*
|
||||
* @param notification The notification to be sent
|
||||
*/
|
||||
public void sendNotification(Notification notification) {
|
||||
|
||||
synchronized (entries) {
|
||||
for (BaseNotificationBroadcasterEntry item : entries) {
|
||||
if ((item.filter != null) &&
|
||||
(!item.filter.isNotificationEnabled(notification)))
|
||||
continue;
|
||||
item.listener.handleNotification(notification, item.handback);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility class representing a particular registered listener entry.
|
||||
*/
|
||||
|
||||
class BaseNotificationBroadcasterEntry {
|
||||
|
||||
public BaseNotificationBroadcasterEntry(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback) {
|
||||
this.listener = listener;
|
||||
this.filter = filter;
|
||||
this.handback = handback;
|
||||
}
|
||||
|
||||
public NotificationFilter filter = null;
|
||||
|
||||
public Object handback = null;
|
||||
|
||||
public NotificationListener listener = null;
|
||||
|
||||
}
|
||||
83
java/org/apache/tomcat/util/modeler/FeatureInfo.java
Normal file
83
java/org/apache/tomcat/util/modeler/FeatureInfo.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.management.MBeanFeatureInfo;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Convenience base class for <code>AttributeInfo</code> and
|
||||
* <code>OperationInfo</code> classes that will be used to collect configuration
|
||||
* information for the <code>ModelMBean</code> beans exposed for management.</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class FeatureInfo implements Serializable {
|
||||
static final long serialVersionUID = -911529176124712296L;
|
||||
|
||||
protected String description = null;
|
||||
protected String name = null;
|
||||
protected MBeanFeatureInfo info = null;
|
||||
|
||||
// all have type except Constructor
|
||||
protected String type = null;
|
||||
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
/**
|
||||
* @return the human-readable description of this feature.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name of this feature, which must be unique among features
|
||||
* in the same collection.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fully qualified Java class name of this element.
|
||||
*/
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
17
java/org/apache/tomcat/util/modeler/LocalStrings.properties
Normal file
17
java/org/apache/tomcat/util/modeler/LocalStrings.properties
Normal file
@@ -0,0 +1,17 @@
|
||||
# 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.
|
||||
|
||||
modules.digesterParseError=Error parsing registry data
|
||||
modules.readDescriptorsError=Error reading descriptors
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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.
|
||||
|
||||
modules.digesterParseError=Erreur lors de l'analyse des données du registre
|
||||
modules.readDescriptorsError=Erreur lors de la lecture des descripteurs
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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.
|
||||
|
||||
modules.digesterParseError=レジストリデータの解析エラー
|
||||
modules.readDescriptorsError=ディスクリプタ読み取り中のエラー
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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.
|
||||
|
||||
modules.digesterParseError=레지스트리 데이터를 파싱하는 중 오류 발생
|
||||
modules.readDescriptorsError=Descriptor들을 읽는 중 오류 발생
|
||||
@@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
modules.readDescriptorsError=读取描述文件出错
|
||||
586
java/org/apache/tomcat/util/modeler/ManagedBean.java
Normal file
586
java/org/apache/tomcat/util/modeler/ManagedBean.java
Normal file
@@ -0,0 +1,586 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import javax.management.ServiceNotFoundException;
|
||||
|
||||
import org.apache.tomcat.util.buf.StringUtils;
|
||||
import org.apache.tomcat.util.buf.StringUtils.Function;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Internal configuration information for a managed bean (MBean)
|
||||
* descriptor.</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class ManagedBean implements java.io.Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String BASE_MBEAN = "org.apache.tomcat.util.modeler.BaseModelMBean";
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
static final Class<?>[] NO_ARGS_PARAM_SIG = new Class[0];
|
||||
|
||||
|
||||
private final ReadWriteLock mBeanInfoLock = new ReentrantReadWriteLock();
|
||||
/**
|
||||
* The <code>ModelMBeanInfo</code> object that corresponds
|
||||
* to this <code>ManagedBean</code> instance.
|
||||
*/
|
||||
private transient volatile MBeanInfo info = null;
|
||||
|
||||
private Map<String,AttributeInfo> attributes = new HashMap<>();
|
||||
|
||||
private Map<String,OperationInfo> operations = new HashMap<>();
|
||||
|
||||
protected String className = BASE_MBEAN;
|
||||
protected String description = null;
|
||||
protected String domain = null;
|
||||
protected String group = null;
|
||||
protected String name = null;
|
||||
|
||||
private NotificationInfo notifications[] = new NotificationInfo[0];
|
||||
protected String type = null;
|
||||
|
||||
/** Constructor. Will add default attributes.
|
||||
*
|
||||
*/
|
||||
public ManagedBean() {
|
||||
AttributeInfo ai=new AttributeInfo();
|
||||
ai.setName("modelerType");
|
||||
ai.setDescription("Type of the modeled resource. Can be set only once");
|
||||
ai.setType("java.lang.String");
|
||||
ai.setWriteable(false);
|
||||
addAttribute(ai);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
|
||||
/**
|
||||
* @return the collection of attributes for this MBean.
|
||||
*/
|
||||
public AttributeInfo[] getAttributes() {
|
||||
AttributeInfo result[] = new AttributeInfo[attributes.size()];
|
||||
attributes.values().toArray(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The fully qualified name of the Java class of the MBean
|
||||
* described by this descriptor. If not specified, the standard JMX
|
||||
* class (<code>javax.management.modelmbean.RequiredModeLMBean</code>)
|
||||
* will be utilized.
|
||||
* @return the class name
|
||||
*/
|
||||
public String getClassName() {
|
||||
return this.className;
|
||||
}
|
||||
|
||||
public void setClassName(String className) {
|
||||
mBeanInfoLock.writeLock().lock();
|
||||
try {
|
||||
this.className = className;
|
||||
this.info = null;
|
||||
} finally {
|
||||
mBeanInfoLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the human-readable description of this MBean.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
mBeanInfoLock.writeLock().lock();
|
||||
try {
|
||||
this.description = description;
|
||||
this.info = null;
|
||||
} finally {
|
||||
mBeanInfoLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the (optional) <code>ObjectName</code> domain in which
|
||||
* this MBean should be registered in the MBeanServer.
|
||||
*/
|
||||
public String getDomain() {
|
||||
return this.domain;
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the (optional) group to which this MBean belongs.
|
||||
*/
|
||||
public String getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
public void setGroup(String group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name of this managed bean, which must be unique
|
||||
* among all MBeans managed by a particular MBeans server.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
mBeanInfoLock.writeLock().lock();
|
||||
try {
|
||||
this.name = name;
|
||||
this.info = null;
|
||||
} finally {
|
||||
mBeanInfoLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the collection of notifications for this MBean.
|
||||
*/
|
||||
public NotificationInfo[] getNotifications() {
|
||||
return this.notifications;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the collection of operations for this MBean.
|
||||
*/
|
||||
public OperationInfo[] getOperations() {
|
||||
OperationInfo[] result = new OperationInfo[operations.size()];
|
||||
operations.values().toArray(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the fully qualified name of the Java class of the resource
|
||||
* implementation class described by the managed bean described
|
||||
* by this descriptor.
|
||||
*/
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
mBeanInfoLock.writeLock().lock();
|
||||
try {
|
||||
this.type = type;
|
||||
this.info = null;
|
||||
} finally {
|
||||
mBeanInfoLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Add a new attribute to the set of attributes for this MBean.
|
||||
*
|
||||
* @param attribute The new attribute descriptor
|
||||
*/
|
||||
public void addAttribute(AttributeInfo attribute) {
|
||||
attributes.put(attribute.getName(), attribute);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a new notification to the set of notifications for this MBean.
|
||||
*
|
||||
* @param notification The new notification descriptor
|
||||
*/
|
||||
public void addNotification(NotificationInfo notification) {
|
||||
mBeanInfoLock.writeLock().lock();
|
||||
try {
|
||||
NotificationInfo results[] =
|
||||
new NotificationInfo[notifications.length + 1];
|
||||
System.arraycopy(notifications, 0, results, 0,
|
||||
notifications.length);
|
||||
results[notifications.length] = notification;
|
||||
notifications = results;
|
||||
this.info = null;
|
||||
} finally {
|
||||
mBeanInfoLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a new operation to the set of operations for this MBean.
|
||||
*
|
||||
* @param operation The new operation descriptor
|
||||
*/
|
||||
public void addOperation(OperationInfo operation) {
|
||||
operations.put(createOperationKey(operation), operation);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create and return a <code>ModelMBean</code> that has been
|
||||
* preconfigured with the <code>ModelMBeanInfo</code> information
|
||||
* for this managed bean, and is associated with the specified
|
||||
* managed object instance. The returned <code>ModelMBean</code>
|
||||
* will <strong>NOT</strong> have been registered with our
|
||||
* <code>MBeanServer</code>.
|
||||
*
|
||||
* @param instance Instanced of the managed object, or <code>null</code>
|
||||
* for no associated instance
|
||||
* @return the MBean
|
||||
* @exception InstanceNotFoundException if the managed resource
|
||||
* object cannot be found
|
||||
* @exception MBeanException if a problem occurs instantiating the
|
||||
* <code>ModelMBean</code> instance
|
||||
* @exception RuntimeOperationsException if a JMX runtime error occurs
|
||||
*/
|
||||
public DynamicMBean createMBean(Object instance)
|
||||
throws InstanceNotFoundException,
|
||||
MBeanException, RuntimeOperationsException {
|
||||
|
||||
BaseModelMBean mbean = null;
|
||||
|
||||
// Load the ModelMBean implementation class
|
||||
if(getClassName().equals(BASE_MBEAN)) {
|
||||
// Skip introspection
|
||||
mbean = new BaseModelMBean();
|
||||
} else {
|
||||
Class<?> clazz = null;
|
||||
Exception ex = null;
|
||||
try {
|
||||
clazz = Class.forName(getClassName());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
if( clazz==null ) {
|
||||
try {
|
||||
ClassLoader cl= Thread.currentThread().getContextClassLoader();
|
||||
if ( cl != null)
|
||||
clazz= cl.loadClass(getClassName());
|
||||
} catch (Exception e) {
|
||||
ex=e;
|
||||
}
|
||||
}
|
||||
|
||||
if( clazz==null) {
|
||||
throw new MBeanException
|
||||
(ex, "Cannot load ModelMBean class " + getClassName());
|
||||
}
|
||||
try {
|
||||
// Stupid - this will set the default minfo first....
|
||||
mbean = (BaseModelMBean) clazz.getConstructor().newInstance();
|
||||
} catch (RuntimeOperationsException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new MBeanException
|
||||
(e, "Cannot instantiate ModelMBean of class " +
|
||||
getClassName());
|
||||
}
|
||||
}
|
||||
|
||||
mbean.setManagedBean(this);
|
||||
|
||||
// Set the managed resource (if any)
|
||||
try {
|
||||
if (instance != null)
|
||||
mbean.setManagedResource(instance, "ObjectReference");
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
return mbean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create and return a <code>ModelMBeanInfo</code> object that
|
||||
* describes this entire managed bean.
|
||||
* @return the MBean info
|
||||
*/
|
||||
MBeanInfo getMBeanInfo() {
|
||||
|
||||
// Return our cached information (if any)
|
||||
mBeanInfoLock.readLock().lock();
|
||||
try {
|
||||
if (info != null) {
|
||||
return info;
|
||||
}
|
||||
} finally {
|
||||
mBeanInfoLock.readLock().unlock();
|
||||
}
|
||||
|
||||
mBeanInfoLock.writeLock().lock();
|
||||
try {
|
||||
if (info == null) {
|
||||
// Create subordinate information descriptors as required
|
||||
AttributeInfo attrs[] = getAttributes();
|
||||
MBeanAttributeInfo attributes[] =
|
||||
new MBeanAttributeInfo[attrs.length];
|
||||
for (int i = 0; i < attrs.length; i++)
|
||||
attributes[i] = attrs[i].createAttributeInfo();
|
||||
|
||||
OperationInfo opers[] = getOperations();
|
||||
MBeanOperationInfo operations[] =
|
||||
new MBeanOperationInfo[opers.length];
|
||||
for (int i = 0; i < opers.length; i++)
|
||||
operations[i] = opers[i].createOperationInfo();
|
||||
|
||||
|
||||
NotificationInfo notifs[] = getNotifications();
|
||||
MBeanNotificationInfo notifications[] =
|
||||
new MBeanNotificationInfo[notifs.length];
|
||||
for (int i = 0; i < notifs.length; i++)
|
||||
notifications[i] = notifs[i].createNotificationInfo();
|
||||
|
||||
|
||||
// Construct and return a new ModelMBeanInfo object
|
||||
info = new MBeanInfo(getClassName(),
|
||||
getDescription(),
|
||||
attributes,
|
||||
new MBeanConstructorInfo[] {},
|
||||
operations,
|
||||
notifications);
|
||||
}
|
||||
|
||||
return info;
|
||||
} finally {
|
||||
mBeanInfoLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a string representation of this managed bean.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder sb = new StringBuilder("ManagedBean[");
|
||||
sb.append("name=");
|
||||
sb.append(name);
|
||||
sb.append(", className=");
|
||||
sb.append(className);
|
||||
sb.append(", description=");
|
||||
sb.append(description);
|
||||
if (group != null) {
|
||||
sb.append(", group=");
|
||||
sb.append(group);
|
||||
}
|
||||
sb.append(", type=");
|
||||
sb.append(type);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
Method getGetter(String aname, BaseModelMBean mbean, Object resource)
|
||||
throws AttributeNotFoundException, ReflectionException {
|
||||
|
||||
Method m = null;
|
||||
|
||||
AttributeInfo attrInfo = attributes.get(aname);
|
||||
// Look up the actual operation to be used
|
||||
if (attrInfo == null)
|
||||
throw new AttributeNotFoundException(" Cannot find attribute " + aname + " for " + resource);
|
||||
|
||||
String getMethod = attrInfo.getGetMethod();
|
||||
if (getMethod == null)
|
||||
throw new AttributeNotFoundException("Cannot find attribute " + aname + " get method name");
|
||||
|
||||
Object object = null;
|
||||
NoSuchMethodException exception = null;
|
||||
try {
|
||||
object = mbean;
|
||||
m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG);
|
||||
} catch (NoSuchMethodException e) {
|
||||
exception = e;
|
||||
}
|
||||
if (m== null && resource != null) {
|
||||
try {
|
||||
object = resource;
|
||||
m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG);
|
||||
exception=null;
|
||||
} catch (NoSuchMethodException e) {
|
||||
exception = e;
|
||||
}
|
||||
}
|
||||
if (exception != null)
|
||||
throw new ReflectionException(exception,
|
||||
"Cannot find getter method " + getMethod);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public Method getSetter(String aname, BaseModelMBean bean, Object resource)
|
||||
throws AttributeNotFoundException, ReflectionException {
|
||||
|
||||
Method m = null;
|
||||
|
||||
AttributeInfo attrInfo = attributes.get(aname);
|
||||
if (attrInfo == null)
|
||||
throw new AttributeNotFoundException(" Cannot find attribute " + aname);
|
||||
|
||||
// Look up the actual operation to be used
|
||||
String setMethod = attrInfo.getSetMethod();
|
||||
if (setMethod == null)
|
||||
throw new AttributeNotFoundException("Cannot find attribute " + aname + " set method name");
|
||||
|
||||
String argType=attrInfo.getType();
|
||||
|
||||
Class<?> signature[] =
|
||||
new Class[] { BaseModelMBean.getAttributeClass( argType ) };
|
||||
|
||||
Object object = null;
|
||||
NoSuchMethodException exception = null;
|
||||
try {
|
||||
object = bean;
|
||||
m = object.getClass().getMethod(setMethod, signature);
|
||||
} catch (NoSuchMethodException e) {
|
||||
exception = e;
|
||||
}
|
||||
if (m == null && resource != null) {
|
||||
try {
|
||||
object = resource;
|
||||
m = object.getClass().getMethod(setMethod, signature);
|
||||
exception=null;
|
||||
} catch (NoSuchMethodException e) {
|
||||
exception = e;
|
||||
}
|
||||
}
|
||||
if (exception != null)
|
||||
throw new ReflectionException(exception,
|
||||
"Cannot find setter method " + setMethod +
|
||||
" " + resource);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public Method getInvoke(String aname, Object[] params, String[] signature, BaseModelMBean bean, Object resource)
|
||||
throws MBeanException, ReflectionException {
|
||||
|
||||
Method method = null;
|
||||
|
||||
if (params == null)
|
||||
params = new Object[0];
|
||||
if (signature == null)
|
||||
signature = new String[0];
|
||||
if (params.length != signature.length)
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException(
|
||||
"Inconsistent arguments and signature"),
|
||||
"Inconsistent arguments and signature");
|
||||
|
||||
// Acquire the ModelMBeanOperationInfo information for
|
||||
// the requested operation
|
||||
OperationInfo opInfo =
|
||||
operations.get(createOperationKey(aname, signature));
|
||||
if (opInfo == null)
|
||||
throw new MBeanException(new ServiceNotFoundException(
|
||||
"Cannot find operation " + aname),
|
||||
"Cannot find operation " + aname);
|
||||
|
||||
// Prepare the signature required by Java reflection APIs
|
||||
// FIXME - should we use the signature from opInfo?
|
||||
Class<?> types[] = new Class[signature.length];
|
||||
for (int i = 0; i < signature.length; i++) {
|
||||
types[i] = BaseModelMBean.getAttributeClass(signature[i]);
|
||||
}
|
||||
|
||||
// Locate the method to be invoked, either in this MBean itself
|
||||
// or in the corresponding managed resource
|
||||
// FIXME - Accessible methods in superinterfaces?
|
||||
Object object = null;
|
||||
Exception exception = null;
|
||||
try {
|
||||
object = bean;
|
||||
method = object.getClass().getMethod(aname, types);
|
||||
} catch (NoSuchMethodException e) {
|
||||
exception = e;
|
||||
}
|
||||
try {
|
||||
if ((method == null) && (resource != null)) {
|
||||
object = resource;
|
||||
method = object.getClass().getMethod(aname, types);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
exception = e;
|
||||
}
|
||||
if (method == null) {
|
||||
throw new ReflectionException(exception, "Cannot find method "
|
||||
+ aname + " with this signature");
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
|
||||
private String createOperationKey(OperationInfo operation) {
|
||||
StringBuilder key = new StringBuilder(operation.getName());
|
||||
key.append('(');
|
||||
StringUtils.join(operation.getSignature(), ',', new Function<ParameterInfo>() {
|
||||
@Override public String apply(ParameterInfo t) { return t.getType(); }}, key);
|
||||
key.append(')');
|
||||
return key.toString().intern();
|
||||
}
|
||||
|
||||
|
||||
private String createOperationKey(String methodName, String[] parameterTypes) {
|
||||
StringBuilder key = new StringBuilder(methodName);
|
||||
key.append('(');
|
||||
StringUtils.join(parameterTypes, ',', key);
|
||||
key.append(')');
|
||||
|
||||
return key.toString().intern();
|
||||
}
|
||||
}
|
||||
156
java/org/apache/tomcat/util/modeler/NotificationInfo.java
Normal file
156
java/org/apache/tomcat/util/modeler/NotificationInfo.java
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
|
||||
/**
|
||||
* <p>Internal configuration information for a <code>Notification</code>
|
||||
* descriptor.</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class NotificationInfo extends FeatureInfo {
|
||||
|
||||
static final long serialVersionUID = -6319885418912650856L;
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The <code>ModelMBeanNotificationInfo</code> object that corresponds
|
||||
* to this <code>NotificationInfo</code> instance.
|
||||
*/
|
||||
transient MBeanNotificationInfo info = null;
|
||||
protected String notifTypes[] = new String[0];
|
||||
protected final ReadWriteLock notifTypesLock = new ReentrantReadWriteLock();
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
|
||||
/**
|
||||
* Override the <code>description</code> property setter.
|
||||
*
|
||||
* @param description The new description
|
||||
*/
|
||||
@Override
|
||||
public void setDescription(String description) {
|
||||
super.setDescription(description);
|
||||
this.info = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Override the <code>name</code> property setter.
|
||||
*
|
||||
* @param name The new name
|
||||
*/
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
super.setName(name);
|
||||
this.info = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the set of notification types for this MBean.
|
||||
*/
|
||||
public String[] getNotifTypes() {
|
||||
Lock readLock = notifTypesLock.readLock();
|
||||
readLock.lock();
|
||||
try {
|
||||
return this.notifTypes;
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Add a new notification type to the set managed by an MBean.
|
||||
*
|
||||
* @param notifType The new notification type
|
||||
*/
|
||||
public void addNotifType(String notifType) {
|
||||
|
||||
Lock writeLock = notifTypesLock.writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
|
||||
String results[] = new String[notifTypes.length + 1];
|
||||
System.arraycopy(notifTypes, 0, results, 0, notifTypes.length);
|
||||
results[notifTypes.length] = notifType;
|
||||
notifTypes = results;
|
||||
this.info = null;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create and return a <code>ModelMBeanNotificationInfo</code> object that
|
||||
* corresponds to the attribute described by this instance.
|
||||
* @return the notification info
|
||||
*/
|
||||
public MBeanNotificationInfo createNotificationInfo() {
|
||||
|
||||
// Return our cached information (if any)
|
||||
if (info != null)
|
||||
return info;
|
||||
|
||||
// Create and return a new information object
|
||||
info = new MBeanNotificationInfo
|
||||
(getNotifTypes(), getName(), getDescription());
|
||||
//Descriptor descriptor = info.getDescriptor();
|
||||
//addFields(descriptor);
|
||||
//info.setDescriptor(descriptor);
|
||||
return info;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a string representation of this notification descriptor.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder sb = new StringBuilder("NotificationInfo[");
|
||||
sb.append("name=");
|
||||
sb.append(name);
|
||||
sb.append(", description=");
|
||||
sb.append(description);
|
||||
sb.append(", notifTypes=");
|
||||
Lock readLock = notifTypesLock.readLock();
|
||||
readLock.lock();
|
||||
try {
|
||||
sb.append(notifTypes.length);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
172
java/org/apache/tomcat/util/modeler/OperationInfo.java
Normal file
172
java/org/apache/tomcat/util/modeler/OperationInfo.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
|
||||
/**
|
||||
* <p>Internal configuration information for an <code>Operation</code>
|
||||
* descriptor.</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class OperationInfo extends FeatureInfo {
|
||||
|
||||
static final long serialVersionUID = 4418342922072614875L;
|
||||
|
||||
// ----------------------------------------------------------- Constructors
|
||||
|
||||
/**
|
||||
* Standard zero-arguments constructor.
|
||||
*/
|
||||
public OperationInfo() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
protected String impact = "UNKNOWN";
|
||||
protected String role = "operation";
|
||||
protected final ReadWriteLock parametersLock = new ReentrantReadWriteLock();
|
||||
protected ParameterInfo parameters[] = new ParameterInfo[0];
|
||||
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
/**
|
||||
* @return the "impact" of this operation, which should be
|
||||
* a (case-insensitive) string value "ACTION", "ACTION_INFO",
|
||||
* "INFO", or "UNKNOWN".
|
||||
*/
|
||||
public String getImpact() {
|
||||
return this.impact;
|
||||
}
|
||||
|
||||
public void setImpact(String impact) {
|
||||
if (impact == null)
|
||||
this.impact = null;
|
||||
else
|
||||
this.impact = impact.toUpperCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the role of this operation ("getter", "setter", "operation", or
|
||||
* "constructor").
|
||||
*/
|
||||
public String getRole() {
|
||||
return this.role;
|
||||
}
|
||||
|
||||
public void setRole(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the fully qualified Java class name of the return type for this
|
||||
* operation.
|
||||
*/
|
||||
public String getReturnType() {
|
||||
if(type == null) {
|
||||
type = "void";
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setReturnType(String returnType) {
|
||||
this.type = returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the set of parameters for this operation.
|
||||
*/
|
||||
public ParameterInfo[] getSignature() {
|
||||
Lock readLock = parametersLock.readLock();
|
||||
readLock.lock();
|
||||
try {
|
||||
return this.parameters;
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Add a new parameter to the set of arguments for this operation.
|
||||
*
|
||||
* @param parameter The new parameter descriptor
|
||||
*/
|
||||
public void addParameter(ParameterInfo parameter) {
|
||||
|
||||
Lock writeLock = parametersLock.writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
ParameterInfo results[] = new ParameterInfo[parameters.length + 1];
|
||||
System.arraycopy(parameters, 0, results, 0, parameters.length);
|
||||
results[parameters.length] = parameter;
|
||||
parameters = results;
|
||||
this.info = null;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create and return a <code>ModelMBeanOperationInfo</code> object that
|
||||
* corresponds to the attribute described by this instance.
|
||||
* @return the operation info
|
||||
*/
|
||||
MBeanOperationInfo createOperationInfo() {
|
||||
|
||||
// Return our cached information (if any)
|
||||
if (info == null) {
|
||||
// Create and return a new information object
|
||||
int impact = MBeanOperationInfo.UNKNOWN;
|
||||
if ("ACTION".equals(getImpact()))
|
||||
impact = MBeanOperationInfo.ACTION;
|
||||
else if ("ACTION_INFO".equals(getImpact()))
|
||||
impact = MBeanOperationInfo.ACTION_INFO;
|
||||
else if ("INFO".equals(getImpact()))
|
||||
impact = MBeanOperationInfo.INFO;
|
||||
|
||||
info = new MBeanOperationInfo(getName(), getDescription(),
|
||||
getMBeanParameterInfo(),
|
||||
getReturnType(), impact);
|
||||
}
|
||||
return (MBeanOperationInfo)info;
|
||||
}
|
||||
|
||||
protected MBeanParameterInfo[] getMBeanParameterInfo() {
|
||||
ParameterInfo params[] = getSignature();
|
||||
MBeanParameterInfo parameters[] =
|
||||
new MBeanParameterInfo[params.length];
|
||||
for (int i = 0; i < params.length; i++)
|
||||
parameters[i] = params[i].createParameterInfo();
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
57
java/org/apache/tomcat/util/modeler/ParameterInfo.java
Normal file
57
java/org/apache/tomcat/util/modeler/ParameterInfo.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
|
||||
import javax.management.MBeanParameterInfo;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Internal configuration information for a <code>Parameter</code>
|
||||
* descriptor.</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class ParameterInfo extends FeatureInfo {
|
||||
static final long serialVersionUID = 2222796006787664020L;
|
||||
// ----------------------------------------------------------- Constructors
|
||||
|
||||
|
||||
/**
|
||||
* Standard zero-arguments constructor.
|
||||
*/
|
||||
public ParameterInfo() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a <code>MBeanParameterInfo</code> object that
|
||||
* corresponds to the parameter described by this instance.
|
||||
* @return a parameter info
|
||||
*/
|
||||
public MBeanParameterInfo createParameterInfo() {
|
||||
|
||||
// Return our cached information (if any)
|
||||
if (info == null) {
|
||||
info = new MBeanParameterInfo
|
||||
(getName(), getType(), getDescription());
|
||||
}
|
||||
return (MBeanParameterInfo)info;
|
||||
}
|
||||
}
|
||||
748
java/org/apache/tomcat/util/modeler/Registry.java
Normal file
748
java/org/apache/tomcat/util/modeler/Registry.java
Normal file
@@ -0,0 +1,748 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanRegistration;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.modeler.modules.ModelerSource;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/*
|
||||
Issues:
|
||||
- exceptions - too many "throws Exception"
|
||||
- double check the interfaces
|
||||
- start removing the use of the experimental methods in tomcat, then remove
|
||||
the methods ( before 1.1 final )
|
||||
- is the security enough to prevent Registry being used to avoid the
|
||||
permission checks in the mbean server ?
|
||||
*/
|
||||
|
||||
/**
|
||||
* Registry for modeler MBeans.
|
||||
*
|
||||
* This is the main entry point into modeler. It provides methods to create and
|
||||
* manipulate model mbeans and simplify their use.
|
||||
*
|
||||
* This class is itself an mbean.
|
||||
*
|
||||
* IMPORTANT: public methods not marked with @since x.x are experimental or
|
||||
* internal. Should not be used.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Costin Manolache
|
||||
*/
|
||||
public class Registry implements RegistryMBean, MBeanRegistration {
|
||||
|
||||
/**
|
||||
* The Log instance to which we will write our log messages.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(Registry.class);
|
||||
private static final StringManager sm = StringManager.getManager(Registry.class);
|
||||
|
||||
// Support for the factory methods
|
||||
|
||||
/**
|
||||
* The registry instance created by our factory method the first time it is
|
||||
* called.
|
||||
*/
|
||||
private static Registry registry = null;
|
||||
|
||||
// Per registry fields
|
||||
|
||||
/**
|
||||
* The <code>MBeanServer</code> instance that we will use to register
|
||||
* management beans.
|
||||
*/
|
||||
private volatile MBeanServer server = null;
|
||||
private final Object serverLock = new Object();
|
||||
|
||||
/**
|
||||
* The set of ManagedBean instances for the beans this registry knows about,
|
||||
* keyed by name.
|
||||
*/
|
||||
private HashMap<String,ManagedBean> descriptors = new HashMap<>();
|
||||
|
||||
/** List of managed beans, keyed by class name
|
||||
*/
|
||||
private HashMap<String,ManagedBean> descriptorsByClass = new HashMap<>();
|
||||
|
||||
// map to avoid duplicated searching or loading descriptors
|
||||
private HashMap<String,URL> searchedPaths = new HashMap<>();
|
||||
|
||||
private Object guard;
|
||||
|
||||
// Id - small ints to use array access. No reset on stop()
|
||||
// Used for notifications
|
||||
private final Hashtable<String,Hashtable<String,Integer>> idDomains =
|
||||
new Hashtable<>();
|
||||
private final Hashtable<String,int[]> ids = new Hashtable<>();
|
||||
|
||||
|
||||
// ----------------------------------------------------------- Constructors
|
||||
|
||||
public Registry() {
|
||||
super();
|
||||
}
|
||||
|
||||
// -------------------- Static methods --------------------
|
||||
// Factories
|
||||
|
||||
/**
|
||||
* Factory method to create (if necessary) and return our
|
||||
* <code>Registry</code> instance.
|
||||
*
|
||||
* @param key Unused
|
||||
* @param guard Prevent access to the registry by untrusted components
|
||||
*
|
||||
* @return the registry
|
||||
* @since 1.1
|
||||
*/
|
||||
public static synchronized Registry getRegistry(Object key, Object guard) {
|
||||
if (registry == null) {
|
||||
registry = new Registry();
|
||||
}
|
||||
if (registry.guard != null && registry.guard != guard) {
|
||||
return null;
|
||||
}
|
||||
return registry;
|
||||
}
|
||||
|
||||
|
||||
/** Lifecycle method - clean up the registry metadata.
|
||||
* Called from resetMetadata().
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
@Override
|
||||
public void stop() {
|
||||
descriptorsByClass = new HashMap<>();
|
||||
descriptors = new HashMap<>();
|
||||
searchedPaths = new HashMap<>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a bean by creating a modeler mbean and adding it to the
|
||||
* MBeanServer.
|
||||
*
|
||||
* If metadata is not loaded, we'll look up and read a file named
|
||||
* "mbeans-descriptors.ser" or "mbeans-descriptors.xml" in the same package
|
||||
* or parent.
|
||||
*
|
||||
* If the bean is an instance of DynamicMBean. it's metadata will be
|
||||
* converted to a model mbean and we'll wrap it - so modeler services will
|
||||
* be supported
|
||||
*
|
||||
* If the metadata is still not found, introspection will be used to extract
|
||||
* it automatically.
|
||||
*
|
||||
* If an mbean is already registered under this name, it'll be first
|
||||
* unregistered.
|
||||
*
|
||||
* If the component implements MBeanRegistration, the methods will be
|
||||
* called. If the method has a method "setRegistry" that takes a
|
||||
* RegistryMBean as parameter, it'll be called with the current registry.
|
||||
*
|
||||
*
|
||||
* @param bean Object to be registered
|
||||
* @param oname Name used for registration
|
||||
* @param type The type of the mbean, as declared in mbeans-descriptors. If
|
||||
* null, the name of the class will be used. This can be used as
|
||||
* a hint or by subclasses.
|
||||
* @throws Exception if a registration error occurred
|
||||
* @since 1.1
|
||||
*/
|
||||
@Override
|
||||
public void registerComponent(Object bean, String oname, String type) throws Exception {
|
||||
registerComponent(bean, new ObjectName(oname), type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unregister a component. We'll first check if it is registered, and mask
|
||||
* all errors. This is mostly a helper.
|
||||
*
|
||||
* @param oname Name used for unregistration
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
@Override
|
||||
public void unregisterComponent(String oname) {
|
||||
try {
|
||||
unregisterComponent(new ObjectName(oname));
|
||||
} catch (MalformedObjectNameException e) {
|
||||
log.info("Error creating object name " + e );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoke a operation on a list of mbeans. Can be used to implement
|
||||
* lifecycle operations.
|
||||
*
|
||||
* @param mbeans list of ObjectName on which we'll invoke the operations
|
||||
* @param operation Name of the operation ( init, start, stop, etc)
|
||||
* @param failFirst If false, exceptions will be ignored
|
||||
* @throws Exception Error invoking operation
|
||||
* @since 1.1
|
||||
*/
|
||||
@Override
|
||||
public void invoke(List<ObjectName> mbeans, String operation, boolean failFirst)
|
||||
throws Exception {
|
||||
|
||||
if (mbeans == null) {
|
||||
return;
|
||||
}
|
||||
for (ObjectName current : mbeans) {
|
||||
try {
|
||||
if (current == null) {
|
||||
continue;
|
||||
}
|
||||
if (getMethodInfo(current, operation) == null) {
|
||||
continue;
|
||||
}
|
||||
getMBeanServer().invoke(current, operation, new Object[] {}, new String[] {});
|
||||
|
||||
} catch (Exception t) {
|
||||
if (failFirst)
|
||||
throw t;
|
||||
log.info("Error initializing " + current + " " + t.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- ID registry --------------------
|
||||
|
||||
/**
|
||||
* Return an int ID for faster access. Will be used for notifications
|
||||
* and for other operations we want to optimize.
|
||||
*
|
||||
* @param domain Namespace
|
||||
* @param name Type of the notification
|
||||
* @return A unique id for the domain:name combination
|
||||
* @since 1.1
|
||||
*/
|
||||
@Override
|
||||
public synchronized int getId(String domain, String name) {
|
||||
if (domain == null) {
|
||||
domain = "";
|
||||
}
|
||||
Hashtable<String, Integer> domainTable = idDomains.get(domain);
|
||||
if (domainTable == null) {
|
||||
domainTable = new Hashtable<>();
|
||||
idDomains.put(domain, domainTable);
|
||||
}
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
Integer i = domainTable.get(name);
|
||||
|
||||
if (i != null) {
|
||||
return i.intValue();
|
||||
}
|
||||
|
||||
int id[] = ids.get(domain);
|
||||
if (id == null) {
|
||||
id = new int[1];
|
||||
ids.put(domain, id);
|
||||
}
|
||||
int code = id[0]++;
|
||||
domainTable.put(name, Integer.valueOf(code));
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
// -------------------- Metadata --------------------
|
||||
// methods from 1.0
|
||||
|
||||
/**
|
||||
* Add a new bean metadata to the set of beans known to this registry. This
|
||||
* is used by internal components.
|
||||
*
|
||||
* @param bean The managed bean to be added
|
||||
* @since 1.0
|
||||
*/
|
||||
public void addManagedBean(ManagedBean bean) {
|
||||
// XXX Use group + name
|
||||
descriptors.put(bean.getName(), bean);
|
||||
if (bean.getType() != null) {
|
||||
descriptorsByClass.put(bean.getType(), bean);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find and return the managed bean definition for the specified bean name,
|
||||
* if any; otherwise return <code>null</code>.
|
||||
*
|
||||
* @param name Name of the managed bean to be returned. Since 1.1, both
|
||||
* short names or the full name of the class can be used.
|
||||
* @return the managed bean
|
||||
* @since 1.0
|
||||
*/
|
||||
public ManagedBean findManagedBean(String name) {
|
||||
// XXX Group ?? Use Group + Type
|
||||
ManagedBean mb = descriptors.get(name);
|
||||
if (mb == null)
|
||||
mb = descriptorsByClass.get(name);
|
||||
return mb;
|
||||
}
|
||||
|
||||
|
||||
// -------------------- Helpers --------------------
|
||||
|
||||
/**
|
||||
* Get the type of an attribute of the object, from the metadata.
|
||||
*
|
||||
* @param oname The bean name
|
||||
* @param attName The attribute name
|
||||
* @return null if metadata about the attribute is not found
|
||||
* @since 1.1
|
||||
*/
|
||||
public String getType(ObjectName oname, String attName) {
|
||||
String type = null;
|
||||
MBeanInfo info = null;
|
||||
try {
|
||||
info = getMBeanServer().getMBeanInfo(oname);
|
||||
} catch (Exception e) {
|
||||
log.info( "Can't find metadata for object" + oname );
|
||||
return null;
|
||||
}
|
||||
|
||||
MBeanAttributeInfo attInfo[] = info.getAttributes();
|
||||
for (int i = 0; i < attInfo.length; i++) {
|
||||
if (attName.equals(attInfo[i].getName())) {
|
||||
type = attInfo[i].getType();
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the operation info for a method
|
||||
*
|
||||
* @param oname The bean name
|
||||
* @param opName The operation name
|
||||
* @return the operation info for the specified operation
|
||||
*/
|
||||
public MBeanOperationInfo getMethodInfo(ObjectName oname, String opName) {
|
||||
MBeanInfo info = null;
|
||||
try {
|
||||
info = getMBeanServer().getMBeanInfo(oname);
|
||||
} catch (Exception e) {
|
||||
log.info( "Can't find metadata " + oname );
|
||||
return null;
|
||||
}
|
||||
MBeanOperationInfo attInfo[] = info.getOperations();
|
||||
for (int i = 0; i < attInfo.length; i++) {
|
||||
if (opName.equals(attInfo[i].getName())) {
|
||||
return attInfo[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the operation info for a method.
|
||||
*
|
||||
* @param oname The bean name
|
||||
* @param opName The operation name
|
||||
* @param argCount The number of arguments to the method
|
||||
* @return the operation info for the specified operation
|
||||
* @throws InstanceNotFoundException If the object name is not bound to an MBean
|
||||
*/
|
||||
public MBeanOperationInfo getMethodInfo(ObjectName oname, String opName, int argCount)
|
||||
throws InstanceNotFoundException
|
||||
{
|
||||
MBeanInfo info = null;
|
||||
try {
|
||||
info = getMBeanServer().getMBeanInfo(oname);
|
||||
} catch (InstanceNotFoundException infe) {
|
||||
throw infe;
|
||||
} catch (Exception e) {
|
||||
log.warn(sm.getString("registry.noMetadata", oname), e);
|
||||
return null;
|
||||
}
|
||||
MBeanOperationInfo attInfo[] = info.getOperations();
|
||||
for (int i = 0; i < attInfo.length; i++) {
|
||||
if (opName.equals(attInfo[i].getName())
|
||||
&& argCount == attInfo[i].getSignature().length) {
|
||||
return attInfo[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a component. This is just a helper that avoids exceptions by
|
||||
* checking if the mbean is already registered
|
||||
*
|
||||
* @param oname The bean name
|
||||
*/
|
||||
public void unregisterComponent(ObjectName oname) {
|
||||
try {
|
||||
if (oname != null && getMBeanServer().isRegistered(oname)) {
|
||||
getMBeanServer().unregisterMBean(oname);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
log.error("Error unregistering mbean", t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory method to create (if necessary) and return our
|
||||
* <code>MBeanServer</code> instance.
|
||||
*
|
||||
* @return the MBean server
|
||||
*/
|
||||
public MBeanServer getMBeanServer() {
|
||||
if (server == null) {
|
||||
synchronized (serverLock) {
|
||||
if (server == null) {
|
||||
long t1 = System.currentTimeMillis();
|
||||
if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
|
||||
server = MBeanServerFactory.findMBeanServer(null).get(0);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Using existing MBeanServer " + (System.currentTimeMillis() - t1));
|
||||
}
|
||||
} else {
|
||||
server = ManagementFactory.getPlatformMBeanServer();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Creating MBeanServer" + (System.currentTimeMillis() - t1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find or load metadata.
|
||||
*
|
||||
* @param bean The bean
|
||||
* @param beanClass The bean class
|
||||
* @param type The registry type
|
||||
* @return the managed bean
|
||||
* @throws Exception An error occurred
|
||||
*/
|
||||
public ManagedBean findManagedBean(Object bean, Class<?> beanClass, String type)
|
||||
throws Exception {
|
||||
|
||||
if (bean != null && beanClass == null) {
|
||||
beanClass = bean.getClass();
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
type = beanClass.getName();
|
||||
}
|
||||
|
||||
// first look for existing descriptor
|
||||
ManagedBean managed = findManagedBean(type);
|
||||
|
||||
// Search for a descriptor in the same package
|
||||
if (managed == null) {
|
||||
// check package and parent packages
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Looking for descriptor ");
|
||||
}
|
||||
findDescriptor(beanClass, type);
|
||||
|
||||
managed = findManagedBean(type);
|
||||
}
|
||||
|
||||
// Still not found - use introspection
|
||||
if (managed == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Introspecting ");
|
||||
}
|
||||
|
||||
// introspection
|
||||
load("MbeansDescriptorsIntrospectionSource", beanClass, type);
|
||||
|
||||
managed = findManagedBean(type);
|
||||
if (managed == null) {
|
||||
log.warn( "No metadata found for " + type );
|
||||
return null;
|
||||
}
|
||||
managed.setName(type);
|
||||
addManagedBean(managed);
|
||||
}
|
||||
return managed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL Convert a string to object, based on type. Used by several
|
||||
* components. We could provide some pluggability. It is here to keep things
|
||||
* consistent and avoid duplication in other tasks
|
||||
*
|
||||
* @param type Fully qualified class name of the resulting value
|
||||
* @param value String value to be converted
|
||||
* @return Converted value
|
||||
*/
|
||||
public Object convertValue(String type, String value) {
|
||||
Object objValue = value;
|
||||
|
||||
if (type == null || "java.lang.String".equals(type)) {
|
||||
// string is default
|
||||
objValue = value;
|
||||
} else if ("javax.management.ObjectName".equals(type) || "ObjectName".equals(type)) {
|
||||
try {
|
||||
objValue = new ObjectName(value);
|
||||
} catch (MalformedObjectNameException e) {
|
||||
return null;
|
||||
}
|
||||
} else if ("java.lang.Integer".equals(type) || "int".equals(type)) {
|
||||
objValue = Integer.valueOf(value);
|
||||
} else if ("java.lang.Long".equals(type) || "long".equals(type)) {
|
||||
objValue = Long.valueOf(value);
|
||||
} else if ("java.lang.Boolean".equals(type) || "boolean".equals(type)) {
|
||||
objValue = Boolean.valueOf(value);
|
||||
}
|
||||
return objValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Experimental. Load descriptors.
|
||||
*
|
||||
* @param sourceType The source type
|
||||
* @param source The bean
|
||||
* @param param A type to load
|
||||
* @return List of descriptors
|
||||
* @throws Exception Error loading descriptors
|
||||
*/
|
||||
public List<ObjectName> load(String sourceType, Object source, String param) throws Exception {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("load " + source);
|
||||
}
|
||||
String location = null;
|
||||
String type = null;
|
||||
Object inputsource = null;
|
||||
|
||||
if (source instanceof URL) {
|
||||
URL url = (URL) source;
|
||||
location = url.toString();
|
||||
type = param;
|
||||
inputsource = url.openStream();
|
||||
if (sourceType == null && location.endsWith(".xml")) {
|
||||
sourceType = "MbeansDescriptorsDigesterSource";
|
||||
}
|
||||
} else if (source instanceof File) {
|
||||
location = ((File) source).getAbsolutePath();
|
||||
inputsource = new FileInputStream((File) source);
|
||||
type = param;
|
||||
if (sourceType == null && location.endsWith(".xml")) {
|
||||
sourceType = "MbeansDescriptorsDigesterSource";
|
||||
}
|
||||
} else if (source instanceof InputStream) {
|
||||
type = param;
|
||||
inputsource = source;
|
||||
} else if (source instanceof Class<?>) {
|
||||
location = ((Class<?>) source).getName();
|
||||
type = param;
|
||||
inputsource = source;
|
||||
if (sourceType == null) {
|
||||
sourceType = "MbeansDescriptorsIntrospectionSource";
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceType == null) {
|
||||
sourceType = "MbeansDescriptorsDigesterSource";
|
||||
}
|
||||
ModelerSource ds = getModelerSource(sourceType);
|
||||
List<ObjectName> mbeans = ds.loadDescriptors(this, type, inputsource);
|
||||
|
||||
return mbeans;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a component
|
||||
*
|
||||
* @param bean The bean
|
||||
* @param oname The object name
|
||||
* @param type The registry type
|
||||
* @throws Exception Error registering component
|
||||
*/
|
||||
public void registerComponent(Object bean, ObjectName oname, String type) throws Exception {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Managed= " + oname);
|
||||
}
|
||||
|
||||
if (bean == null) {
|
||||
log.error("Null component " + oname );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (type == null) {
|
||||
type = bean.getClass().getName();
|
||||
}
|
||||
|
||||
ManagedBean managed = findManagedBean(null, bean.getClass(), type);
|
||||
|
||||
// The real mbean is created and registered
|
||||
DynamicMBean mbean = managed.createMBean(bean);
|
||||
|
||||
if (getMBeanServer().isRegistered(oname)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Unregistering existing component " + oname);
|
||||
}
|
||||
getMBeanServer().unregisterMBean(oname);
|
||||
}
|
||||
|
||||
getMBeanServer().registerMBean(mbean, oname);
|
||||
} catch (Exception ex) {
|
||||
log.error("Error registering " + oname, ex );
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lookup the component descriptor in the package and in the parent
|
||||
* packages.
|
||||
*
|
||||
* @param packageName The package name
|
||||
* @param classLoader The class loader
|
||||
*/
|
||||
public void loadDescriptors(String packageName, ClassLoader classLoader) {
|
||||
String res = packageName.replace('.', '/');
|
||||
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Finding descriptor " + res);
|
||||
}
|
||||
|
||||
if (searchedPaths.get(packageName) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String descriptors = res + "/mbeans-descriptors.xml";
|
||||
URL dURL = classLoader.getResource(descriptors);
|
||||
|
||||
if (dURL == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Found " + dURL);
|
||||
searchedPaths.put(packageName, dURL);
|
||||
try {
|
||||
load("MbeansDescriptorsDigesterSource", dURL, null);
|
||||
} catch(Exception ex ) {
|
||||
log.error("Error loading " + dURL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lookup the component descriptor in the package and in the parent
|
||||
* packages.
|
||||
*/
|
||||
private void findDescriptor(Class<?> beanClass, String type) {
|
||||
if (type == null) {
|
||||
type = beanClass.getName();
|
||||
}
|
||||
ClassLoader classLoader = null;
|
||||
if (beanClass != null) {
|
||||
classLoader = beanClass.getClassLoader();
|
||||
}
|
||||
if (classLoader == null) {
|
||||
classLoader = Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
if (classLoader == null) {
|
||||
classLoader = this.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
String className = type;
|
||||
String pkg = className;
|
||||
while (pkg.indexOf(".") > 0) {
|
||||
int lastComp = pkg.lastIndexOf(".");
|
||||
if (lastComp <= 0)
|
||||
return;
|
||||
pkg = pkg.substring(0, lastComp);
|
||||
if (searchedPaths.get(pkg) != null) {
|
||||
return;
|
||||
}
|
||||
loadDescriptors(pkg, classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ModelerSource getModelerSource(String type) throws Exception {
|
||||
if (type == null)
|
||||
type = "MbeansDescriptorsDigesterSource";
|
||||
if (!type.contains(".")) {
|
||||
type = "org.apache.tomcat.util.modeler.modules." + type;
|
||||
}
|
||||
|
||||
Class<?> c = Class.forName(type);
|
||||
ModelerSource ds = (ModelerSource) c.getConstructor().newInstance();
|
||||
return ds;
|
||||
}
|
||||
|
||||
|
||||
// -------------------- Registration --------------------
|
||||
|
||||
@Override
|
||||
public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
|
||||
synchronized (serverLock) {
|
||||
this.server = server;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void postRegister(Boolean registrationDone) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void preDeregister() throws Exception {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void postDeregister() {
|
||||
}
|
||||
}
|
||||
120
java/org/apache/tomcat/util/modeler/RegistryMBean.java
Normal file
120
java/org/apache/tomcat/util/modeler/RegistryMBean.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* Interface for modeler MBeans.
|
||||
*
|
||||
* This is the main entry point into modeler. It provides methods to create
|
||||
* and manipulate model mbeans and simplify their use.
|
||||
*
|
||||
* Starting with version 1.1, this is no longer a singleton and the static
|
||||
* methods are strongly deprecated. In a container environment we can expect
|
||||
* different applications to use different registries.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Costin Manolache
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
public interface RegistryMBean {
|
||||
|
||||
/**
|
||||
* Invoke an operation on a set of mbeans.
|
||||
*
|
||||
* @param mbeans List of ObjectNames
|
||||
* @param operation Operation to perform. Typically "init" "start" "stop" or "destroy"
|
||||
* @param failFirst Behavior in case of exceptions - if false we'll ignore
|
||||
* errors
|
||||
* @throws Exception Error invoking operation
|
||||
*/
|
||||
public void invoke(List<ObjectName> mbeans, String operation, boolean failFirst)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Register a bean by creating a modeler mbean and adding it to the
|
||||
* MBeanServer.
|
||||
*
|
||||
* If metadata is not loaded, we'll look up and read a file named
|
||||
* "mbeans-descriptors.ser" or "mbeans-descriptors.xml" in the same package
|
||||
* or parent.
|
||||
*
|
||||
* If the bean is an instance of DynamicMBean. it's metadata will be converted
|
||||
* to a model mbean and we'll wrap it - so modeler services will be supported
|
||||
*
|
||||
* If the metadata is still not found, introspection will be used to extract
|
||||
* it automatically.
|
||||
*
|
||||
* If an mbean is already registered under this name, it'll be first
|
||||
* unregistered.
|
||||
*
|
||||
* If the component implements MBeanRegistration, the methods will be called.
|
||||
* If the method has a method "setRegistry" that takes a RegistryMBean as
|
||||
* parameter, it'll be called with the current registry.
|
||||
*
|
||||
*
|
||||
* @param bean Object to be registered
|
||||
* @param oname Name used for registration
|
||||
* @param type The type of the mbean, as declared in mbeans-descriptors. If
|
||||
* null, the name of the class will be used. This can be used as a hint or
|
||||
* by subclasses.
|
||||
* @throws Exception Error registering MBean
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
public void registerComponent(Object bean, String oname, String type)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Unregister a component. We'll first check if it is registered,
|
||||
* and mask all errors. This is mostly a helper.
|
||||
*
|
||||
* @param oname The name used by the bean
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
public void unregisterComponent(String oname);
|
||||
|
||||
|
||||
/**
|
||||
* Return an int ID for faster access. Will be used for notifications
|
||||
* and for other operations we want to optimize.
|
||||
*
|
||||
* @param domain Namespace
|
||||
* @param name Type of the notification
|
||||
* @return A unique id for the domain:name combination
|
||||
* @since 1.1
|
||||
*/
|
||||
public int getId(String domain, String name);
|
||||
|
||||
|
||||
/**
|
||||
* Reset all metadata cached by this registry. Should be called
|
||||
* to support reloading. Existing mbeans will not be affected or modified.
|
||||
*
|
||||
* It will be called automatically if the Registry is unregistered.
|
||||
* @since 1.1
|
||||
*/
|
||||
public void stop();
|
||||
}
|
||||
34
java/org/apache/tomcat/util/modeler/Util.java
Normal file
34
java/org/apache/tomcat/util/modeler/Util.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler;
|
||||
|
||||
public class Util {
|
||||
|
||||
private Util() {
|
||||
// Utility class. Hide default constructor.
|
||||
}
|
||||
|
||||
public static boolean objectNameValueNeedsQuote(String input) {
|
||||
for (int i = 0; i < input.length(); i++) {
|
||||
char ch = input.charAt(i);
|
||||
if (ch == ',' || ch == '=' || ch == ':' || ch == '*' || ch == '?') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
247
java/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd
Normal file
247
java/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd
Normal file
@@ -0,0 +1,247 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
DTD for the Model MBeans Configuration File
|
||||
|
||||
To support validation of your configuration file, include the following
|
||||
DOCTYPE element at the beginning (after the "xml" declaration):
|
||||
|
||||
<!DOCTYPE mbeans-descriptors PUBLIC
|
||||
"-//Apache Software Foundation//DTD Model MBeans Configuration File"
|
||||
"http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
|
||||
-->
|
||||
|
||||
|
||||
<!-- ========== Defined Types ============================================= -->
|
||||
|
||||
|
||||
<!-- A "Boolean" is the string representation of a boolean (true or false)
|
||||
variable.
|
||||
-->
|
||||
<!ENTITY % Boolean "(true|false|yes|no)">
|
||||
|
||||
|
||||
<!-- A "ClassName" is the fully qualified name of a Java class that is
|
||||
instantiated to provide the functionality of the enclosing element.
|
||||
-->
|
||||
<!ENTITY % ClassName "CDATA">
|
||||
|
||||
|
||||
<!-- A "MethodName" is the name of a constructor or method, which must
|
||||
be legal according to the syntax requirements of the Java language.
|
||||
-->
|
||||
<!ENTITY % MethodName "CDATA">
|
||||
|
||||
|
||||
<!-- A "VariableName" is the name of a variable or parameter, which must
|
||||
be legal according to the syntax requirements of the Java language.
|
||||
-->
|
||||
<!ENTITY % VariableName "CDATA">
|
||||
|
||||
|
||||
<!-- ========== Element Definitions ======================================= -->
|
||||
|
||||
|
||||
<!-- The "mbeans-descriptors" element is the root of the configuration file
|
||||
hierarchy, and contains nested elements for all of the other
|
||||
configuration settings. Remaining element definitions are listed
|
||||
in alphabetical order.
|
||||
-->
|
||||
<!ELEMENT mbeans-descriptors (mbean*)>
|
||||
<!ATTLIST mbeans-descriptors id ID #IMPLIED>
|
||||
|
||||
|
||||
<!-- The "attribute" element describes a JavaBeans property of an MBean.
|
||||
The following attributes are supported:
|
||||
|
||||
description Human-readable description of this attribute.
|
||||
|
||||
displayName Display name of this attribute.
|
||||
|
||||
getMethod Name of the property getter method, if it does
|
||||
not follow standard JavaBeans naming patterns.
|
||||
|
||||
is Boolean value indicating whether or not this
|
||||
attribute is a boolean with an "is" getter method.
|
||||
By default, this is set to "false".
|
||||
|
||||
name Name of this JavaBeans property, conforming to
|
||||
standard naming design patterns.
|
||||
|
||||
readable Boolean value indicating whether or not this
|
||||
attribute is readable by management applications.
|
||||
By default, this is set to "true".
|
||||
|
||||
setMethod Name of the property setter method, if it does
|
||||
not follow standard JavaBeans naming patterns.
|
||||
|
||||
type Fully qualified Java class name of this attribute.
|
||||
|
||||
writeable Boolean value indicating whether or not this
|
||||
attribute is writeable by management applications.
|
||||
By default, this is set to "true".
|
||||
-->
|
||||
<!ELEMENT attribute (descriptor?)>
|
||||
<!ATTLIST attribute id ID #IMPLIED>
|
||||
<!ATTLIST attribute description CDATA #IMPLIED>
|
||||
<!ATTLIST attribute displayName CDATA #IMPLIED>
|
||||
<!ATTLIST attribute getMethod %MethodName; #IMPLIED>
|
||||
<!ATTLIST attribute is %Boolean; #IMPLIED>
|
||||
<!ATTLIST attribute name %VariableName; #IMPLIED>
|
||||
<!ATTLIST attribute readable %Boolean; #IMPLIED>
|
||||
<!ATTLIST attribute setMethod %MethodName; #IMPLIED>
|
||||
<!ATTLIST attribute type %ClassName; #IMPLIED>
|
||||
<!ATTLIST attribute writeable %Boolean; #IMPLIED>
|
||||
|
||||
|
||||
<!-- The "constructor" element describes a public constructor for the
|
||||
underlying actual class. It may contain nested "parameter" elements
|
||||
for the various arguments to this constructor. The following attributes
|
||||
are supported:
|
||||
|
||||
displayName Display name of this constructor.
|
||||
|
||||
name Name of this constructor (by Java convention, this must
|
||||
be the same as the base class name).
|
||||
-->
|
||||
<!ELEMENT constructor (descriptor?, parameter*)>
|
||||
<!ATTLIST constructor id ID #IMPLIED>
|
||||
<!ATTLIST constructor displayName CDATA #IMPLIED>
|
||||
<!ATTLIST constructor name %VariableName; #IMPLIED>
|
||||
|
||||
|
||||
<!-- The "descriptor" element groups a set of descriptor fields whose
|
||||
values will be included in the Descriptor for the corresponding
|
||||
metadata info classes.
|
||||
-->
|
||||
<!ELEMENT descriptor (field*)>
|
||||
<!ATTLIST descriptor id ID #IMPLIED>
|
||||
|
||||
|
||||
<!-- The "field" element represents a single name/value pair that will
|
||||
be included in the Descriptor corresponding to our enclosing
|
||||
"descriptor" element. The following attributes are supported:
|
||||
|
||||
name Field name of the field to be included
|
||||
|
||||
value Field value of the field to be included
|
||||
(will be stored as a String)
|
||||
-->
|
||||
<!ELEMENT field EMPTY>
|
||||
<!ATTLIST field id ID #IMPLIED>
|
||||
<!ATTLIST field name CDATA #REQUIRED>
|
||||
<!ATTLIST field value CDATA #REQUIRED>
|
||||
|
||||
|
||||
|
||||
<!-- The "mbean" element describes a particular JMX ModelMBean implementation,
|
||||
including the information necessary to construct the corresponding
|
||||
ModelMBeanInfo structures. The following attributes are supported:
|
||||
|
||||
className Fully qualified Java class name of the ModelMBean
|
||||
implementation class. If not specified, the standard
|
||||
implementation provided by JMX will be utilized.
|
||||
|
||||
description Human-readable description of this managed bean.
|
||||
|
||||
domain The JMX MBeanServer domain in which the ModelMBean
|
||||
created by this managed bean should be registered,
|
||||
when creating its ObjectName.
|
||||
|
||||
group Optional name of a "grouping classification" that can
|
||||
be used to select groups of similar MBean implementation
|
||||
classes.
|
||||
|
||||
name Unique name of this MBean (normally corresponds to the
|
||||
base class name of the corresponding server component).
|
||||
|
||||
type Fully qualified Java class name of the underlying
|
||||
managed resource implementation class.
|
||||
-->
|
||||
<!ELEMENT mbean (descriptor?, attribute*, constructor*, notification*, operation*)>
|
||||
<!ATTLIST mbean id ID #IMPLIED>
|
||||
<!ATTLIST mbean className %ClassName; #IMPLIED>
|
||||
<!ATTLIST mbean description CDATA #IMPLIED>
|
||||
<!ATTLIST mbean domain CDATA #IMPLIED>
|
||||
<!ATTLIST mbean group CDATA #IMPLIED>
|
||||
<!ATTLIST mbean name %MethodName; #IMPLIED>
|
||||
<!ATTLIST mbean type %ClassName; #IMPLIED>
|
||||
|
||||
|
||||
<!-- The "notification" element describes the notification types that are
|
||||
generated by a particular managed bean. The following attributes
|
||||
are supported:
|
||||
|
||||
description Human-readable description of these notification events.
|
||||
|
||||
name Name of this set of notification event types.
|
||||
-->
|
||||
<!ELEMENT notification (descriptor?, notification-type*)>
|
||||
<!ATTLIST notification id ID #IMPLIED>
|
||||
<!ATTLIST notification description CDATA #IMPLIED>
|
||||
<!ATTLIST notification name %VariableName; #IMPLIED>
|
||||
|
||||
|
||||
<!-- The nested content of the "notification-type" element is the event string
|
||||
of an event that can be emitted by this MBean.
|
||||
-->
|
||||
<!ELEMENT notification-type (#PCDATA)>
|
||||
<!ATTLIST notification-type id ID #IMPLIED>
|
||||
|
||||
|
||||
<!-- The "operation" element describes a the signature of a public method
|
||||
that is accessible to management applications. The following attributes
|
||||
are supported:
|
||||
|
||||
description Human-readable description of this operation.
|
||||
|
||||
impact Indication of the impact of this method:
|
||||
ACTION (write like), ACTION-INFO (write+read like)
|
||||
INFO (read like), or UNKNOWN.
|
||||
|
||||
name Name of this public method.
|
||||
|
||||
returnType Fully qualified Java class name of the return
|
||||
type of this method.
|
||||
-->
|
||||
<!ELEMENT operation (descriptor?, parameter*)>
|
||||
<!ATTLIST operation id ID #IMPLIED>
|
||||
<!ATTLIST operation description CDATA #IMPLIED>
|
||||
<!ATTLIST operation impact CDATA #IMPLIED>
|
||||
<!ATTLIST operation name %VariableName; #IMPLIED>
|
||||
<!ATTLIST operation returnType %ClassName; #IMPLIED>
|
||||
|
||||
|
||||
<!-- The "parameter" element describes a single argument that will be passed
|
||||
to a constructor or operation. The following attributes are supported:
|
||||
|
||||
description Human-readable description of this parameter.
|
||||
|
||||
name Java language name of this parameter.
|
||||
|
||||
type Fully qualified Java class name of this parameter.
|
||||
-->
|
||||
<!ELEMENT parameter EMPTY>
|
||||
<!ATTLIST parameter id ID #IMPLIED>
|
||||
<!ATTLIST parameter description CDATA #IMPLIED>
|
||||
<!ATTLIST parameter name %VariableName; #IMPLIED>
|
||||
<!ATTLIST parameter type %ClassName; #IMPLIED>
|
||||
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler.modules;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.digester.Digester;
|
||||
import org.apache.tomcat.util.modeler.ManagedBean;
|
||||
import org.apache.tomcat.util.modeler.Registry;
|
||||
|
||||
public class MbeansDescriptorsDigesterSource extends ModelerSource
|
||||
{
|
||||
private static final Log log =
|
||||
LogFactory.getLog(MbeansDescriptorsDigesterSource.class);
|
||||
private static final Object dLock = new Object();
|
||||
|
||||
private Registry registry;
|
||||
private final List<ObjectName> mbeans = new ArrayList<>();
|
||||
private static Digester digester = null;
|
||||
|
||||
private static Digester createDigester() {
|
||||
|
||||
Digester digester = new Digester();
|
||||
digester.setNamespaceAware(false);
|
||||
digester.setValidating(false);
|
||||
URL url = Registry.getRegistry(null, null).getClass().getResource
|
||||
("/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd");
|
||||
digester.register
|
||||
("-//Apache Software Foundation//DTD Model MBeans Configuration File",
|
||||
url.toString());
|
||||
|
||||
// Configure the parsing rules
|
||||
digester.addObjectCreate
|
||||
("mbeans-descriptors/mbean",
|
||||
"org.apache.tomcat.util.modeler.ManagedBean");
|
||||
digester.addSetProperties
|
||||
("mbeans-descriptors/mbean");
|
||||
digester.addSetNext
|
||||
("mbeans-descriptors/mbean",
|
||||
"add",
|
||||
"java.lang.Object");
|
||||
|
||||
digester.addObjectCreate
|
||||
("mbeans-descriptors/mbean/attribute",
|
||||
"org.apache.tomcat.util.modeler.AttributeInfo");
|
||||
digester.addSetProperties
|
||||
("mbeans-descriptors/mbean/attribute");
|
||||
digester.addSetNext
|
||||
("mbeans-descriptors/mbean/attribute",
|
||||
"addAttribute",
|
||||
"org.apache.tomcat.util.modeler.AttributeInfo");
|
||||
|
||||
digester.addObjectCreate
|
||||
("mbeans-descriptors/mbean/notification",
|
||||
"org.apache.tomcat.util.modeler.NotificationInfo");
|
||||
digester.addSetProperties
|
||||
("mbeans-descriptors/mbean/notification");
|
||||
digester.addSetNext
|
||||
("mbeans-descriptors/mbean/notification",
|
||||
"addNotification",
|
||||
"org.apache.tomcat.util.modeler.NotificationInfo");
|
||||
|
||||
digester.addObjectCreate
|
||||
("mbeans-descriptors/mbean/notification/descriptor/field",
|
||||
"org.apache.tomcat.util.modeler.FieldInfo");
|
||||
digester.addSetProperties
|
||||
("mbeans-descriptors/mbean/notification/descriptor/field");
|
||||
digester.addSetNext
|
||||
("mbeans-descriptors/mbean/notification/descriptor/field",
|
||||
"addField",
|
||||
"org.apache.tomcat.util.modeler.FieldInfo");
|
||||
|
||||
digester.addCallMethod
|
||||
("mbeans-descriptors/mbean/notification/notification-type",
|
||||
"addNotifType", 0);
|
||||
|
||||
digester.addObjectCreate
|
||||
("mbeans-descriptors/mbean/operation",
|
||||
"org.apache.tomcat.util.modeler.OperationInfo");
|
||||
digester.addSetProperties
|
||||
("mbeans-descriptors/mbean/operation");
|
||||
digester.addSetNext
|
||||
("mbeans-descriptors/mbean/operation",
|
||||
"addOperation",
|
||||
"org.apache.tomcat.util.modeler.OperationInfo");
|
||||
|
||||
digester.addObjectCreate
|
||||
("mbeans-descriptors/mbean/operation/descriptor/field",
|
||||
"org.apache.tomcat.util.modeler.FieldInfo");
|
||||
digester.addSetProperties
|
||||
("mbeans-descriptors/mbean/operation/descriptor/field");
|
||||
digester.addSetNext
|
||||
("mbeans-descriptors/mbean/operation/descriptor/field",
|
||||
"addField",
|
||||
"org.apache.tomcat.util.modeler.FieldInfo");
|
||||
|
||||
digester.addObjectCreate
|
||||
("mbeans-descriptors/mbean/operation/parameter",
|
||||
"org.apache.tomcat.util.modeler.ParameterInfo");
|
||||
digester.addSetProperties
|
||||
("mbeans-descriptors/mbean/operation/parameter");
|
||||
digester.addSetNext
|
||||
("mbeans-descriptors/mbean/operation/parameter",
|
||||
"addParameter",
|
||||
"org.apache.tomcat.util.modeler.ParameterInfo");
|
||||
|
||||
return digester;
|
||||
|
||||
}
|
||||
|
||||
public void setRegistry(Registry reg) {
|
||||
this.registry=reg;
|
||||
}
|
||||
|
||||
|
||||
public void setSource( Object source ) {
|
||||
this.source=source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ObjectName> loadDescriptors( Registry registry, String type,
|
||||
Object source) throws Exception {
|
||||
setRegistry(registry);
|
||||
setSource(source);
|
||||
execute();
|
||||
return mbeans;
|
||||
}
|
||||
|
||||
public void execute() throws Exception {
|
||||
if (registry == null) {
|
||||
registry = Registry.getRegistry(null, null);
|
||||
}
|
||||
|
||||
InputStream stream = (InputStream) source;
|
||||
|
||||
List<ManagedBean> loadedMbeans = new ArrayList<>();
|
||||
synchronized(dLock) {
|
||||
if (digester == null) {
|
||||
digester = createDigester();
|
||||
}
|
||||
|
||||
// Process the input file to configure our registry
|
||||
try {
|
||||
// Push our registry object onto the stack
|
||||
digester.push(loadedMbeans);
|
||||
digester.parse(stream);
|
||||
} catch (Exception e) {
|
||||
log.error(sm.getString("modules.digesterParseError"), e);
|
||||
throw e;
|
||||
} finally {
|
||||
digester.reset();
|
||||
}
|
||||
|
||||
}
|
||||
for (ManagedBean loadedMbean : loadedMbeans) {
|
||||
registry.addManagedBean(loadedMbean);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler.modules;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.modeler.AttributeInfo;
|
||||
import org.apache.tomcat.util.modeler.ManagedBean;
|
||||
import org.apache.tomcat.util.modeler.OperationInfo;
|
||||
import org.apache.tomcat.util.modeler.ParameterInfo;
|
||||
import org.apache.tomcat.util.modeler.Registry;
|
||||
|
||||
public class MbeansDescriptorsIntrospectionSource extends ModelerSource
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(MbeansDescriptorsIntrospectionSource.class);
|
||||
|
||||
private Registry registry;
|
||||
private String type;
|
||||
private final List<ObjectName> mbeans = new ArrayList<>();
|
||||
|
||||
public void setRegistry(Registry reg) {
|
||||
this.registry=reg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used if a single component is loaded
|
||||
*
|
||||
* @param type The type
|
||||
*/
|
||||
public void setType( String type ) {
|
||||
this.type=type;
|
||||
}
|
||||
|
||||
public void setSource( Object source ) {
|
||||
this.source=source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ObjectName> loadDescriptors(Registry registry, String type,
|
||||
Object source) throws Exception {
|
||||
setRegistry(registry);
|
||||
setType(type);
|
||||
setSource(source);
|
||||
execute();
|
||||
return mbeans;
|
||||
}
|
||||
|
||||
public void execute() throws Exception {
|
||||
if( registry==null ) registry=Registry.getRegistry(null, null);
|
||||
try {
|
||||
ManagedBean managed = createManagedBean(registry, null,
|
||||
(Class<?>)source, type);
|
||||
if( managed==null ) return;
|
||||
managed.setName( type );
|
||||
|
||||
registry.addManagedBean(managed);
|
||||
|
||||
} catch( Exception ex ) {
|
||||
log.error(sm.getString("modules.readDescriptorsError"), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------ Implementation for non-declared introspection classes
|
||||
|
||||
private static final Hashtable<String,String> specialMethods = new Hashtable<>();
|
||||
static {
|
||||
specialMethods.put( "preDeregister", "");
|
||||
specialMethods.put( "postDeregister", "");
|
||||
}
|
||||
|
||||
private static final Class<?>[] supportedTypes = new Class[] {
|
||||
Boolean.class,
|
||||
Boolean.TYPE,
|
||||
Byte.class,
|
||||
Byte.TYPE,
|
||||
Character.class,
|
||||
Character.TYPE,
|
||||
Short.class,
|
||||
Short.TYPE,
|
||||
Integer.class,
|
||||
Integer.TYPE,
|
||||
Long.class,
|
||||
Long.TYPE,
|
||||
Float.class,
|
||||
Float.TYPE,
|
||||
Double.class,
|
||||
Double.TYPE,
|
||||
String.class,
|
||||
String[].class,
|
||||
BigDecimal.class,
|
||||
BigInteger.class,
|
||||
ObjectName.class,
|
||||
Object[].class,
|
||||
java.io.File.class,
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this class is one of the supported types.
|
||||
* If the class is supported, returns true. Otherwise,
|
||||
* returns false.
|
||||
* @param ret The class to check
|
||||
* @return boolean True if class is supported
|
||||
*/
|
||||
private boolean supportedType(Class<?> ret) {
|
||||
for (int i = 0; i < supportedTypes.length; i++) {
|
||||
if (ret == supportedTypes[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (isBeanCompatible(ret)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this class conforms to JavaBeans specifications.
|
||||
* If the class is conformant, returns true.
|
||||
*
|
||||
* @param javaType The class to check
|
||||
* @return boolean True if the class is compatible.
|
||||
*/
|
||||
private boolean isBeanCompatible(Class<?> javaType) {
|
||||
// Must be a non-primitive and non array
|
||||
if (javaType.isArray() || javaType.isPrimitive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Anything in the java or javax package that
|
||||
// does not have a defined mapping is excluded.
|
||||
if (javaType.getName().startsWith("java.") ||
|
||||
javaType.getName().startsWith("javax.")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
javaType.getConstructor(new Class[]{});
|
||||
} catch (java.lang.NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure superclass is compatible
|
||||
Class<?> superClass = javaType.getSuperclass();
|
||||
if (superClass != null &&
|
||||
superClass != java.lang.Object.class &&
|
||||
superClass != java.lang.Exception.class &&
|
||||
superClass != java.lang.Throwable.class) {
|
||||
if (!isBeanCompatible(superClass)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the methods and extract 'attributes', methods, etc.
|
||||
*
|
||||
* @param realClass The class to process
|
||||
* @param methods The methods to process
|
||||
* @param attMap The attribute map (complete)
|
||||
* @param getAttMap The readable attributes map
|
||||
* @param setAttMap The settable attributes map
|
||||
* @param invokeAttMap The invokable attributes map
|
||||
*/
|
||||
private void initMethods(Class<?> realClass, Method methods[], Hashtable<String,Method> attMap,
|
||||
Hashtable<String,Method> getAttMap, Hashtable<String,Method> setAttMap,
|
||||
Hashtable<String,Method> invokeAttMap) {
|
||||
|
||||
for (int j = 0; j < methods.length; ++j) {
|
||||
String name = methods[j].getName();
|
||||
|
||||
if (Modifier.isStatic(methods[j].getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
if (!Modifier.isPublic(methods[j].getModifiers())) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Not public " + methods[j] );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (methods[j].getDeclaringClass() == Object.class) {
|
||||
continue;
|
||||
}
|
||||
Class<?> params[] = methods[j].getParameterTypes();
|
||||
|
||||
if (name.startsWith("get") && params.length==0) {
|
||||
Class<?> ret = methods[j].getReturnType();
|
||||
if (!supportedType(ret)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Unsupported type " + methods[j]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
name=unCapitalize(name.substring(3));
|
||||
|
||||
getAttMap.put(name, methods[j]);
|
||||
// just a marker, we don't use the value
|
||||
attMap.put(name, methods[j]);
|
||||
} else if(name.startsWith("is") && params.length == 0) {
|
||||
Class<?> ret = methods[j].getReturnType();
|
||||
if (Boolean.TYPE != ret) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Unsupported type " + methods[j] + " " + ret );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
name = unCapitalize(name.substring(2));
|
||||
|
||||
getAttMap.put(name, methods[j]);
|
||||
// just a marker, we don't use the value
|
||||
attMap.put(name, methods[j]);
|
||||
|
||||
} else if (name.startsWith("set") && params.length == 1) {
|
||||
if (!supportedType(params[0])) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Unsupported type " + methods[j] + " " + params[0]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
name = unCapitalize(name.substring(3));
|
||||
setAttMap.put(name, methods[j]);
|
||||
attMap.put(name, methods[j]);
|
||||
} else {
|
||||
if (params.length == 0) {
|
||||
if (specialMethods.get(methods[j].getName()) != null) {
|
||||
continue;
|
||||
}
|
||||
invokeAttMap.put(name, methods[j]);
|
||||
} else {
|
||||
boolean supported = true;
|
||||
for (int i = 0; i < params.length; i++ ) {
|
||||
if (!supportedType(params[i])) {
|
||||
supported = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (supported) {
|
||||
invokeAttMap.put( name, methods[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* XXX Find if the 'className' is the name of the MBean or
|
||||
* the real class ( I suppose first )
|
||||
* XXX Read (optional) descriptions from a .properties, generated
|
||||
* from source
|
||||
* XXX Deal with constructors
|
||||
*
|
||||
* @param registry The Bean registry (not used)
|
||||
* @param domain The bean domain (not used)
|
||||
* @param realClass The class to analyze
|
||||
* @param type The bean type
|
||||
* @return ManagedBean The create MBean
|
||||
*/
|
||||
public ManagedBean createManagedBean(Registry registry, String domain,
|
||||
Class<?> realClass, String type)
|
||||
{
|
||||
ManagedBean mbean= new ManagedBean();
|
||||
|
||||
Method methods[]=null;
|
||||
|
||||
Hashtable<String,Method> attMap = new Hashtable<>();
|
||||
// key: attribute val: getter method
|
||||
Hashtable<String,Method> getAttMap = new Hashtable<>();
|
||||
// key: attribute val: setter method
|
||||
Hashtable<String,Method> setAttMap = new Hashtable<>();
|
||||
// key: operation val: invoke method
|
||||
Hashtable<String,Method> invokeAttMap = new Hashtable<>();
|
||||
|
||||
methods = realClass.getMethods();
|
||||
|
||||
initMethods(realClass, methods, attMap, getAttMap, setAttMap, invokeAttMap );
|
||||
|
||||
try {
|
||||
|
||||
Enumeration<String> en = attMap.keys();
|
||||
while( en.hasMoreElements() ) {
|
||||
String name = en.nextElement();
|
||||
AttributeInfo ai=new AttributeInfo();
|
||||
ai.setName( name );
|
||||
Method gm = getAttMap.get(name);
|
||||
if( gm!=null ) {
|
||||
//ai.setGetMethodObj( gm );
|
||||
ai.setGetMethod( gm.getName());
|
||||
Class<?> t=gm.getReturnType();
|
||||
if( t!=null )
|
||||
ai.setType( t.getName() );
|
||||
}
|
||||
Method sm = setAttMap.get(name);
|
||||
if( sm!=null ) {
|
||||
//ai.setSetMethodObj(sm);
|
||||
Class<?> t = sm.getParameterTypes()[0];
|
||||
if( t!=null )
|
||||
ai.setType( t.getName());
|
||||
ai.setSetMethod( sm.getName());
|
||||
}
|
||||
ai.setDescription("Introspected attribute " + name);
|
||||
if( log.isDebugEnabled()) log.debug("Introspected attribute " +
|
||||
name + " " + gm + " " + sm);
|
||||
if( gm==null )
|
||||
ai.setReadable(false);
|
||||
if( sm==null )
|
||||
ai.setWriteable(false);
|
||||
if( sm!=null || gm!=null )
|
||||
mbean.addAttribute(ai);
|
||||
}
|
||||
|
||||
// This map is populated by iterating the methods (which end up as
|
||||
// values in the Map) and obtaining the key from the value. It is
|
||||
// impossible for a key to be associated with a null value.
|
||||
for (Entry<String,Method> entry : invokeAttMap.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
Method m = entry.getValue();
|
||||
|
||||
OperationInfo op=new OperationInfo();
|
||||
op.setName(name);
|
||||
op.setReturnType(m.getReturnType().getName());
|
||||
op.setDescription("Introspected operation " + name);
|
||||
Class<?> parms[] = m.getParameterTypes();
|
||||
for(int i=0; i<parms.length; i++ ) {
|
||||
ParameterInfo pi=new ParameterInfo();
|
||||
pi.setType(parms[i].getName());
|
||||
pi.setName(("param" + i).intern());
|
||||
pi.setDescription(("Introspected parameter param" + i).intern());
|
||||
op.addParameter(pi);
|
||||
}
|
||||
mbean.addOperation(op);
|
||||
}
|
||||
|
||||
if( log.isDebugEnabled())
|
||||
log.debug("Setting name: " + type );
|
||||
mbean.setName( type );
|
||||
|
||||
return mbean;
|
||||
} catch( Exception ex ) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------- Utils --------------------
|
||||
/**
|
||||
* Converts the first character of the given
|
||||
* String into lower-case.
|
||||
*
|
||||
* @param name The string to convert
|
||||
* @return String
|
||||
*/
|
||||
private static String unCapitalize(String name) {
|
||||
if (name == null || name.length() == 0) {
|
||||
return name;
|
||||
}
|
||||
char chars[] = name.toCharArray();
|
||||
chars[0] = Character.toLowerCase(chars[0]);
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.apache.tomcat.util.modeler.modules;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.tomcat.util.modeler.Registry;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Source for descriptor data. More sources can be added.
|
||||
*/
|
||||
public abstract class ModelerSource {
|
||||
protected static final StringManager sm = StringManager.getManager(Registry.class);
|
||||
protected Object source;
|
||||
|
||||
/**
|
||||
* Load data, returns a list of items.
|
||||
*
|
||||
* @param registry The registry
|
||||
* @param type The bean registry type
|
||||
* @param source Introspected object or some other source
|
||||
* @return a list of object names
|
||||
* @throws Exception Error loading descriptors
|
||||
*/
|
||||
public abstract List<ObjectName> loadDescriptors(Registry registry,
|
||||
String type, Object source) throws Exception;
|
||||
}
|
||||
59
java/org/apache/tomcat/util/modeler/modules/package.html
Normal file
59
java/org/apache/tomcat/util/modeler/modules/package.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>org.apache.commons.modeler.modules</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Implementation classes - should not be used directly. The API is not stable
|
||||
but eventually the code will be refactored as a collection of mbeans that will be useable
|
||||
( more or less ) independently.</p>
|
||||
|
||||
<p>The MbeanDescriptors* classes are used to extract metadata from different sources. They
|
||||
are result of few stages of refactoring - now they look very similar with ant tasks and are
|
||||
close to normal mbeans, with an execute() method. DOM, SER, Introspection and Dynamic mbean
|
||||
will load metadata from the corresponding sources.
|
||||
</p>
|
||||
|
||||
<p>MbeansSource will load an extended MLET file, similar with jboss. It is not completely
|
||||
implemented - only modeler mbeans and dynamic mbeans are loaded. The important characteristic
|
||||
is that all declared mbeans will be registered in the mbean server as model mbeans. For
|
||||
regular java classes, the description will be used to construct the model mbean. DynamicMbeans
|
||||
metadata will be converted to model mbean and the model mbean wrapper will be loaded.</p>
|
||||
|
||||
<p>The goal of MbeansSource is to implement a simple persistence mechanism. Since all components
|
||||
are model mbeans, we can detect all changes. The source will be loaded as DOM and modifications
|
||||
will be made to the tree. The save() method will save the DOM tree - preserving all comments
|
||||
and having only the changes that are needed.</p>
|
||||
|
||||
<p>There are few remaining issues. First, we need to use the persistence metadata to avoid
|
||||
saving transient fields ( we save an attribute when we detect a change - but we don't know
|
||||
if this attribute should be saved ). The solution is to use the persistence fields in the
|
||||
spec - with some reasonable defaults or patterns for introspection or backward compat.
|
||||
</p>
|
||||
|
||||
<p>Another problem is implementing adding and removing components. In catalina, a
|
||||
factory is used to create the components, and save will operate on all mbeans.
|
||||
For creation we need to also use a factory - using the "Type" as a parameter. This
|
||||
will also work very well with Ant1.6 where we can use the component factory to
|
||||
do a "natural" mapping ( i.e. mbeans can be treated as tasks, with attributes as
|
||||
task attributes ). The second part can be solve by either using a parameter on
|
||||
the factory method ( saveTo ? ), or by having a single mbeans source per domain.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
248
java/org/apache/tomcat/util/modeler/package.html
Normal file
248
java/org/apache/tomcat/util/modeler/package.html
Normal file
@@ -0,0 +1,248 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Package Documentation for COMMONS-MODELER</title>
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<p>The <em>Modeler</em> component of the Commons project
|
||||
offers convenient support for configuring and instantiating Model MBeans
|
||||
(management beans), as described in the JMX Specification. It is typically
|
||||
used within a server-based application that wants to expose management
|
||||
features via JMX. See the
|
||||
<a href="http://java.sun.com/products/JavaManagement/download.html">
|
||||
JMX Specification (Version 1.1)</a> for more information about Model MBeans
|
||||
and other JMX concepts.</p>
|
||||
|
||||
<p>Model MBeans are very powerful - and the JMX specification includes a
|
||||
mechanism to use a standard JMX-provided base class to satisfy many of the
|
||||
requirements, without having to create custom Model MBean implementation
|
||||
classes yourself. However, one of the requirements in creating such a
|
||||
Model MBean is to create the corresponding metadata information (i.e. an
|
||||
implementation of the
|
||||
<code>javax.management.modelmbean.ModelMBeanInfo</code> interface and its
|
||||
corresponding subordinate interfaces). Creating this information can be
|
||||
tedious and error prone. The <em>Modeler</em> package makes the process
|
||||
much simpler, because the required information is constructed dynamically
|
||||
from an easy-to-understand XML description of the metadata. Once you have
|
||||
the metadata defined, and registered at runtime in the provided
|
||||
<a href="Registry.html">Registry</a>, <em>Modeler</em> also supports
|
||||
convenient factory methods to instantiate new Model MBean instances for you.
|
||||
</p>
|
||||
|
||||
<p>The steps required to use Modeler in your server-based application are
|
||||
described in detail below. You can find some simple usage code in the unit
|
||||
tests that come with Modeler (in the <code>src/test</code> subdirectory of the
|
||||
source distribution), and much more complex usage code in Tomcat 4.1 (in the
|
||||
<code>org.apache.catalina.mbeans</code> package).</p>. More advanced uses can
|
||||
be found in Tomcat 5.
|
||||
|
||||
|
||||
<h2>1. Acquire a JMX Implementation</h2>
|
||||
|
||||
<p><em>Modeler</em> has been tested with different JMX implementations:
|
||||
<ul>
|
||||
<li>JMX Reference Implementation (version 1.0.1 or later) -
|
||||
<a href="http://java.sun.com/products/JavaManagement/download.html">
|
||||
http://java.sun.com/products/JavaManagement/download.html</a></li>
|
||||
<li>MX4J (version 1.1 or later) -
|
||||
<a href="http://mx4j.sourceforge.net/">http://mx4j.sourceforge.net</a></li>
|
||||
<li>JBoss MX
|
||||
<a href="http://www.jboss.org/">http://www.jboss.org</a></li>
|
||||
</ul>
|
||||
|
||||
<p>After unpacking the release, you will need to ensure that the appropriate
|
||||
JAR file (<code>jmxri.jar</code> or <code>mx4j.jar</code>) is included on your
|
||||
compilation classpath, and in the classpath of your server application when it
|
||||
is executed.</p>
|
||||
|
||||
|
||||
<h2>2. Create a Modeler Configuration File</h2>
|
||||
|
||||
<p><em>Modeler</em> requires that you construct a configuration file that
|
||||
describes the metadata ultimately need to construct the
|
||||
<code>javax.management.modelmbean.ModelMBeanInfo</code> structure that is
|
||||
required by JMX. Your XML file must conform to the
|
||||
<a href="../../../../../../mbeans-descriptors.dtd">mbeans-descriptors.dtd</a>
|
||||
DTD that defines the acceptable structure.</p>
|
||||
|
||||
<p>Fundamentally, you will be constructing an <code><mbean></code>
|
||||
element for each type of Model MBean that a registry will know how to create.
|
||||
Nested within this element will be other elements describing the constructors,
|
||||
attributes, operations, and notifications associated with this MBean. See
|
||||
the comments in the DTD for detailed information about the valid attributes
|
||||
and their meanings.</p>
|
||||
|
||||
<p>A simple example configuration file might include the following components
|
||||
(abstracted from the real definitions found in Tomcat 4.1's use of Modeler):
|
||||
</p>
|
||||
<pre>
|
||||
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE mbeans-descriptors PUBLIC
|
||||
"-//Apache Software Foundation//DTD Model MBeans Configuration File"
|
||||
"http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
|
||||
|
||||
<mbeans-descriptors>
|
||||
|
||||
<!-- ... other MBean definitions ... -->
|
||||
|
||||
<mbean name="Group"
|
||||
className="org.apache.catalina.mbeans.GroupMBean"
|
||||
description="Group from a user database"
|
||||
domain="Users"
|
||||
group="Group"
|
||||
type="org.apache.catalina.Group">
|
||||
|
||||
<attribute name="description"
|
||||
description="Description of this group"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="groupname"
|
||||
description="Group name of this group"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="roles"
|
||||
description="MBean Names of roles for this group"
|
||||
type="java.lang.String[]"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="users"
|
||||
description="MBean Names of user members of this group"
|
||||
type="java.lang.String[]"
|
||||
writeable="false"/>
|
||||
|
||||
<operation name="addRole"
|
||||
description="Add a new authorized role for this group"
|
||||
impact="ACTION"
|
||||
returnType="void">
|
||||
<parameter name="role"
|
||||
description="Role to be added"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="removeRole"
|
||||
description="Remove an old authorized role for this group"
|
||||
impact="ACTION"
|
||||
returnType="void">
|
||||
<parameter name="role"
|
||||
description="Role to be removed"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="removeRoles"
|
||||
description="Remove all authorized roles for this group"
|
||||
impact="ACTION"
|
||||
returnType="void">
|
||||
</operation>
|
||||
|
||||
</mbean>
|
||||
|
||||
<!-- ... other MBean definitions ... -->
|
||||
|
||||
</mbeans-descriptors>
|
||||
|
||||
</pre>
|
||||
|
||||
<p>This MBean represents an instance of <em>org.apache.catalina.Group</em>,
|
||||
which is an entity representing a group of users (with a shared set of security
|
||||
roles that all users in the group inherit) in a user database. This MBean
|
||||
advertises support for four attributes (description, groupname, roles, and
|
||||
users) that roughly correspond to JavaBean properties. By default, attributes
|
||||
are assumed to have read/write access. For this particular MBean, the roles
|
||||
and users attributes are read-only (<code>writeable="false"</code>). Finally,
|
||||
this MBean supports three operations (addRole, removeRole, and
|
||||
removeRoles) that roughly correspond to JavaBean methods on the underlying
|
||||
component.</p>
|
||||
|
||||
<p>In general, <em>Modeler</em> provides a standard ModelMBean implementation
|
||||
that simply passes on JMX calls on attributes and operations directly through
|
||||
to the managed component that the ModelMBean is associated with. For special
|
||||
case requirements, you can define a subclass of
|
||||
<a href="BaseModelMBean.html">BaseModelMBean</a> that provides override
|
||||
methods for one or more of these attributes (i.e. the property getter and/or
|
||||
setter methods) and operations (i.e. direct method calls).
|
||||
|
||||
<p>For this particular MBean, a custom BaseModelMBean implementation subclass
|
||||
is described (<code>org.apache.catalina.mbeans.GroupMBean</code>) is
|
||||
configured. It was necessary in this particular case because several of the
|
||||
underlying Catalina component's methods deal with internal objects or arrays of
|
||||
objects, rather than just the Strings and primitives that are supported by all
|
||||
JMX clients. Thus, the following method on the <code>Group</code> interface:
|
||||
</p>
|
||||
<pre>
|
||||
public void addRole(Role role);
|
||||
</pre>
|
||||
<p>is represented, in the MBean, by an <code>addRole</code> method that takes
|
||||
a String argument representing the role name of the required role. The MBean's
|
||||
implementation class acts as an adapter, and looks up the required Role
|
||||
object (by name) before calling the <code>addRole</code> method on the
|
||||
underlying <code>Group</code> instance within the Server.</p>
|
||||
|
||||
|
||||
<h2>3. Create Modeler Registry at Startup Time</h2>
|
||||
|
||||
<p>The metadata information, and the corresponding Model MBean factory, is
|
||||
represented at runtime in an instance of <a href="Registry.html">Registry</a>
|
||||
whose contents are initialized from the configuration file prepared as was
|
||||
described above. Typically, such a file will be included in the JAR file
|
||||
containing the MBean implementation classes themselves, and loaded as follows:
|
||||
</p>
|
||||
<pre>
|
||||
URL url= this.getClass().getResource
|
||||
("/com/mycompany/mypackage/mbeans-descriptors.xml");
|
||||
Registry registry = Registry.getRegistry();
|
||||
registry.loadMetadata(url);
|
||||
</pre>
|
||||
|
||||
<p>Besides using the configuration file, it is possible to configure the
|
||||
registry metadata by hand, using the <code>addManagedBean()</code> and
|
||||
<code>removeManagedBean()</code> methods. However, most users will find
|
||||
the standard support for loading a configuration file to be convenient
|
||||
and sufficient.</p>
|
||||
|
||||
<p>Modeler will also look for an mbeans-descriptors.xml in the same package
|
||||
with the class being registered and in its parent. If no metadata is found,
|
||||
modeler will use a number of simple patterns, similar with the ones used by
|
||||
ant, to determine a reasonable metadata</p>
|
||||
|
||||
<p>In a future version we should also support xdoclet-based generation of the
|
||||
descriptors</p>
|
||||
|
||||
|
||||
<h2>4. Instantiate Model MBeans As Needed</h2>
|
||||
|
||||
<p>When your server application needs to instantiate a new MBean and register
|
||||
it with the corresponding <code>MBeanServer</code>, it can execute code like
|
||||
this:</p>
|
||||
|
||||
<pre>
|
||||
Group group = ... managed component instance ...;
|
||||
|
||||
MBeanServer mserver = registry.getMBeanServer();
|
||||
|
||||
String oname="myDomain:type=Group,name=myGroup";
|
||||
|
||||
registry.registerComponent( group, oname, "Group" );
|
||||
</pre>
|
||||
|
||||
<p>After the Model MBean has been created and registered, it is accessible to
|
||||
JMX clients through the standard JMX client APIs.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user