From: remm A ModelMBean implementation for the
diff --git a/java/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java b/java/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java
index ab40612d3..07476652d 100644
--- a/java/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java
+++ b/java/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java
@@ -31,9 +31,9 @@ import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Role;
import org.apache.catalina.User;
import org.apache.catalina.UserDatabase;
-import org.apache.commons.modeler.Registry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.modeler.Registry;
/**
diff --git a/java/org/apache/catalina/mbeans/GroupMBean.java b/java/org/apache/catalina/mbeans/GroupMBean.java
index 63f929879..15b28efee 100644
--- a/java/org/apache/catalina/mbeans/GroupMBean.java
+++ b/java/org/apache/catalina/mbeans/GroupMBean.java
@@ -29,10 +29,10 @@ import javax.management.RuntimeOperationsException;
import org.apache.catalina.Group;
import org.apache.catalina.Role;
import org.apache.catalina.User;
-import org.apache.commons.modeler.BaseModelMBean;
-import org.apache.commons.modeler.ManagedBean;
-import org.apache.commons.modeler.Registry;
import org.apache.tomcat.util.compat.JdkCompat;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.ManagedBean;
+import org.apache.tomcat.util.modeler.Registry;
/**
* A ModelMBean implementation for the
diff --git a/java/org/apache/catalina/mbeans/MBeanFactory.java b/java/org/apache/catalina/mbeans/MBeanFactory.java
index 2664d857f..5c6592b95 100644
--- a/java/org/apache/catalina/mbeans/MBeanFactory.java
+++ b/java/org/apache/catalina/mbeans/MBeanFactory.java
@@ -52,8 +52,8 @@ import org.apache.catalina.valves.RemoteAddrValve;
import org.apache.catalina.valves.RemoteHostValve;
import org.apache.catalina.valves.RequestDumperValve;
import org.apache.catalina.valves.ValveBase;
-import org.apache.commons.modeler.BaseModelMBean;
-import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.Registry;
/**
diff --git a/java/org/apache/catalina/mbeans/MBeanUtils.java b/java/org/apache/catalina/mbeans/MBeanUtils.java
index a7d6a95dd..3f142f003 100644
--- a/java/org/apache/catalina/mbeans/MBeanUtils.java
+++ b/java/org/apache/catalina/mbeans/MBeanUtils.java
@@ -48,9 +48,9 @@ import org.apache.catalina.deploy.NamingResources;
import org.apache.catalina.valves.ValveBase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.commons.modeler.ManagedBean;
-import org.apache.commons.modeler.Registry;
import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.modeler.ManagedBean;
+import org.apache.tomcat.util.modeler.Registry;
/**
diff --git a/java/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java b/java/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java
index 38cdcbb46..ce2ab0501 100644
--- a/java/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java
+++ b/java/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java
@@ -28,10 +28,10 @@ import org.apache.catalina.Group;
import org.apache.catalina.Role;
import org.apache.catalina.User;
import org.apache.catalina.UserDatabase;
-import org.apache.commons.modeler.BaseModelMBean;
-import org.apache.commons.modeler.ManagedBean;
-import org.apache.commons.modeler.Registry;
import org.apache.tomcat.util.compat.JdkCompat;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.ManagedBean;
+import org.apache.tomcat.util.modeler.Registry;
/**
* A ModelMBean implementation for the
diff --git a/java/org/apache/catalina/mbeans/NamingResourcesMBean.java b/java/org/apache/catalina/mbeans/NamingResourcesMBean.java
index e8cb7bffb..202050966 100644
--- a/java/org/apache/catalina/mbeans/NamingResourcesMBean.java
+++ b/java/org/apache/catalina/mbeans/NamingResourcesMBean.java
@@ -27,10 +27,10 @@ import org.apache.catalina.deploy.ContextEnvironment;
import org.apache.catalina.deploy.ContextResource;
import org.apache.catalina.deploy.ContextResourceLink;
import org.apache.catalina.deploy.NamingResources;
-import org.apache.commons.modeler.BaseModelMBean;
-import org.apache.commons.modeler.ManagedBean;
-import org.apache.commons.modeler.Registry;
import org.apache.tomcat.util.compat.JdkCompat;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.ManagedBean;
+import org.apache.tomcat.util.modeler.Registry;
/**
* A ModelMBean implementation for the
diff --git a/java/org/apache/catalina/mbeans/RoleMBean.java b/java/org/apache/catalina/mbeans/RoleMBean.java
index a0aa3576b..541c57af9 100644
--- a/java/org/apache/catalina/mbeans/RoleMBean.java
+++ b/java/org/apache/catalina/mbeans/RoleMBean.java
@@ -21,9 +21,9 @@ import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.RuntimeOperationsException;
-import org.apache.commons.modeler.BaseModelMBean;
-import org.apache.commons.modeler.ManagedBean;
-import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.ManagedBean;
+import org.apache.tomcat.util.modeler.Registry;
/**
diff --git a/java/org/apache/catalina/mbeans/StandardContextMBean.java b/java/org/apache/catalina/mbeans/StandardContextMBean.java
index 9000af6c4..a4c414709 100644
--- a/java/org/apache/catalina/mbeans/StandardContextMBean.java
+++ b/java/org/apache/catalina/mbeans/StandardContextMBean.java
@@ -28,10 +28,10 @@ import org.apache.catalina.deploy.ContextEnvironment;
import org.apache.catalina.deploy.ContextResource;
import org.apache.catalina.deploy.ContextResourceLink;
import org.apache.catalina.deploy.NamingResources;
-import org.apache.commons.modeler.BaseModelMBean;
-import org.apache.commons.modeler.ManagedBean;
-import org.apache.commons.modeler.Registry;
import org.apache.tomcat.util.compat.JdkCompat;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.ManagedBean;
+import org.apache.tomcat.util.modeler.Registry;
/**
* A ModelMBean implementation for the
diff --git a/java/org/apache/catalina/mbeans/StandardEngineMBean.java b/java/org/apache/catalina/mbeans/StandardEngineMBean.java
index 23e677ceb..6e4e6a87e 100644
--- a/java/org/apache/catalina/mbeans/StandardEngineMBean.java
+++ b/java/org/apache/catalina/mbeans/StandardEngineMBean.java
@@ -21,7 +21,7 @@ import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.RuntimeOperationsException;
-import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
/**
diff --git a/java/org/apache/catalina/mbeans/StandardHostMBean.java b/java/org/apache/catalina/mbeans/StandardHostMBean.java
index 8a73359a8..4555710e5 100644
--- a/java/org/apache/catalina/mbeans/StandardHostMBean.java
+++ b/java/org/apache/catalina/mbeans/StandardHostMBean.java
@@ -23,9 +23,9 @@ import javax.management.RuntimeOperationsException;
import org.apache.catalina.Valve;
import org.apache.catalina.core.StandardHost;
-import org.apache.commons.modeler.BaseModelMBean;
-import org.apache.commons.modeler.ManagedBean;
-import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.ManagedBean;
+import org.apache.tomcat.util.modeler.Registry;
/**
diff --git a/java/org/apache/catalina/mbeans/StandardServerMBean.java b/java/org/apache/catalina/mbeans/StandardServerMBean.java
index 2a22ce1c8..94b8547bc 100644
--- a/java/org/apache/catalina/mbeans/StandardServerMBean.java
+++ b/java/org/apache/catalina/mbeans/StandardServerMBean.java
@@ -24,7 +24,7 @@ import javax.management.RuntimeOperationsException;
import org.apache.catalina.Server;
import org.apache.catalina.ServerFactory;
import org.apache.catalina.core.StandardServer;
-import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
/**
diff --git a/java/org/apache/catalina/mbeans/StandardServiceMBean.java b/java/org/apache/catalina/mbeans/StandardServiceMBean.java
index 83f506976..503996d9d 100644
--- a/java/org/apache/catalina/mbeans/StandardServiceMBean.java
+++ b/java/org/apache/catalina/mbeans/StandardServiceMBean.java
@@ -21,7 +21,7 @@ import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.RuntimeOperationsException;
-import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
/**
diff --git a/java/org/apache/catalina/mbeans/UserMBean.java b/java/org/apache/catalina/mbeans/UserMBean.java
index 07a97a5d3..ee315f74a 100644
--- a/java/org/apache/catalina/mbeans/UserMBean.java
+++ b/java/org/apache/catalina/mbeans/UserMBean.java
@@ -29,10 +29,10 @@ import javax.management.RuntimeOperationsException;
import org.apache.catalina.Group;
import org.apache.catalina.Role;
import org.apache.catalina.User;
-import org.apache.commons.modeler.BaseModelMBean;
-import org.apache.commons.modeler.ManagedBean;
-import org.apache.commons.modeler.Registry;
import org.apache.tomcat.util.compat.JdkCompat;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.ManagedBean;
+import org.apache.tomcat.util.modeler.Registry;
/**
* A ModelMBean implementation for the
diff --git a/java/org/apache/catalina/realm/RealmBase.java b/java/org/apache/catalina/realm/RealmBase.java
index 25d374061..4a0e3b707 100644
--- a/java/org/apache/catalina/realm/RealmBase.java
+++ b/java/org/apache/catalina/realm/RealmBase.java
@@ -52,7 +52,7 @@ import org.apache.catalina.util.MD5Encoder;
import org.apache.catalina.util.StringManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.modeler.Registry;
/**
* Simple implementation of Realm that reads an XML file to configure
diff --git a/java/org/apache/catalina/session/ManagerBase.java b/java/org/apache/catalina/session/ManagerBase.java
index 7213a0f44..a033ce615 100644
--- a/java/org/apache/catalina/session/ManagerBase.java
+++ b/java/org/apache/catalina/session/ManagerBase.java
@@ -48,7 +48,7 @@ import org.apache.catalina.core.StandardHost;
import org.apache.catalina.util.StringManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.modeler.Registry;
/**
diff --git a/java/org/apache/catalina/startup/HostConfig.java b/java/org/apache/catalina/startup/HostConfig.java
index ab20c5ee1..fae222475 100644
--- a/java/org/apache/catalina/startup/HostConfig.java
+++ b/java/org/apache/catalina/startup/HostConfig.java
@@ -41,8 +41,8 @@ import org.apache.catalina.LifecycleListener;
import org.apache.catalina.core.ContainerBase;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.util.StringManager;
-import org.apache.commons.modeler.Registry;
import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.modeler.Registry;
/**
diff --git a/java/org/apache/coyote/ajp/AjpAprProtocol.java b/java/org/apache/coyote/ajp/AjpAprProtocol.java
index 3fb2c3915..9e3ebfcf9 100644
--- a/java/org/apache/coyote/ajp/AjpAprProtocol.java
+++ b/java/org/apache/coyote/ajp/AjpAprProtocol.java
@@ -25,13 +25,13 @@ import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
-import org.apache.commons.modeler.Registry;
import org.apache.coyote.ActionCode;
import org.apache.coyote.ActionHook;
import org.apache.coyote.Adapter;
import org.apache.coyote.ProtocolHandler;
import org.apache.coyote.RequestGroupInfo;
import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.net.AprEndpoint;
import org.apache.tomcat.util.net.AprEndpoint.Handler;
import org.apache.tomcat.util.res.StringManager;
diff --git a/java/org/apache/coyote/http11/Http11AprProtocol.java b/java/org/apache/coyote/http11/Http11AprProtocol.java
index c6b4e29a0..8c71250e5 100644
--- a/java/org/apache/coyote/http11/Http11AprProtocol.java
+++ b/java/org/apache/coyote/http11/Http11AprProtocol.java
@@ -25,13 +25,13 @@ import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
-import org.apache.commons.modeler.Registry;
import org.apache.coyote.ActionCode;
import org.apache.coyote.ActionHook;
import org.apache.coyote.Adapter;
import org.apache.coyote.ProtocolHandler;
import org.apache.coyote.RequestGroupInfo;
import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.net.AprEndpoint;
import org.apache.tomcat.util.net.AprEndpoint.Handler;
import org.apache.tomcat.util.res.StringManager;
diff --git a/java/org/apache/coyote/http11/Http11Protocol.java b/java/org/apache/coyote/http11/Http11Protocol.java
index 96323c20c..95cd8d83a 100644
--- a/java/org/apache/coyote/http11/Http11Protocol.java
+++ b/java/org/apache/coyote/http11/Http11Protocol.java
@@ -20,8 +20,8 @@ import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
-import org.apache.commons.modeler.Registry;
import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.threads.ThreadPool;
import org.apache.tomcat.util.threads.ThreadWithAttributes;
diff --git a/java/org/apache/jk/common/ChannelNioSocket.java b/java/org/apache/jk/common/ChannelNioSocket.java
index b51b350e0..9302d5a05 100644
--- a/java/org/apache/jk/common/ChannelNioSocket.java
+++ b/java/org/apache/jk/common/ChannelNioSocket.java
@@ -45,7 +45,6 @@ import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
-import org.apache.commons.modeler.Registry;
import org.apache.jk.core.JkHandler;
import org.apache.jk.core.Msg;
import org.apache.jk.core.MsgContext;
@@ -54,6 +53,7 @@ import org.apache.jk.core.WorkerEnv;
import org.apache.coyote.Request;
import org.apache.coyote.RequestGroupInfo;
import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.threads.ThreadPool;
import org.apache.tomcat.util.threads.ThreadPoolRunnable;
diff --git a/java/org/apache/jk/common/ChannelSocket.java b/java/org/apache/jk/common/ChannelSocket.java
index 5b7153004..c49833d7d 100644
--- a/java/org/apache/jk/common/ChannelSocket.java
+++ b/java/org/apache/jk/common/ChannelSocket.java
@@ -36,7 +36,6 @@ import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
-import org.apache.commons.modeler.Registry;
import org.apache.jk.core.JkHandler;
import org.apache.jk.core.Msg;
import org.apache.jk.core.MsgContext;
@@ -45,6 +44,7 @@ import org.apache.jk.core.WorkerEnv;
import org.apache.coyote.Request;
import org.apache.coyote.RequestGroupInfo;
import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.threads.ThreadPool;
import org.apache.tomcat.util.threads.ThreadPoolRunnable;
diff --git a/java/org/apache/jk/common/ChannelUn.java b/java/org/apache/jk/common/ChannelUn.java
index 281fa816f..1253db91d 100644
--- a/java/org/apache/jk/common/ChannelUn.java
+++ b/java/org/apache/jk/common/ChannelUn.java
@@ -22,7 +22,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import javax.management.ObjectName;
-import org.apache.commons.modeler.Registry;
import org.apache.jk.core.JkHandler;
import org.apache.jk.core.Msg;
import org.apache.jk.core.MsgContext;
@@ -31,6 +30,7 @@ import org.apache.jk.core.WorkerEnv;
import org.apache.coyote.Request;
import org.apache.coyote.RequestGroupInfo;
import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.threads.ThreadPool;
import org.apache.tomcat.util.threads.ThreadPoolRunnable;
diff --git a/java/org/apache/jk/common/JniHandler.java b/java/org/apache/jk/common/JniHandler.java
index 27824a698..46e176a9a 100644
--- a/java/org/apache/jk/common/JniHandler.java
+++ b/java/org/apache/jk/common/JniHandler.java
@@ -20,7 +20,6 @@ import java.io.IOException;
import javax.management.ObjectName;
-import org.apache.commons.modeler.Registry;
import org.apache.jk.apr.AprImpl;
import org.apache.jk.core.JkHandler;
import org.apache.jk.core.Msg;
@@ -29,6 +28,7 @@ import org.apache.jk.core.JkChannel;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.C2BConverter;
import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.modeler.Registry;
/**
diff --git a/java/org/apache/jk/common/ModJkMX.java b/java/org/apache/jk/common/ModJkMX.java
index 4220784f8..7fa732e9d 100644
--- a/java/org/apache/jk/common/ModJkMX.java
+++ b/java/org/apache/jk/common/ModJkMX.java
@@ -33,11 +33,11 @@ import javax.management.Attribute;
import javax.management.ObjectName;
import org.apache.jk.core.JkHandler;
-import org.apache.commons.modeler.Registry;
-import org.apache.commons.modeler.BaseModelMBean;
-import org.apache.commons.modeler.ManagedBean;
-import org.apache.commons.modeler.AttributeInfo;
-import org.apache.commons.modeler.OperationInfo;
+import org.apache.tomcat.util.modeler.AttributeInfo;
+import org.apache.tomcat.util.modeler.BaseModelMBean;
+import org.apache.tomcat.util.modeler.ManagedBean;
+import org.apache.tomcat.util.modeler.OperationInfo;
+import org.apache.tomcat.util.modeler.Registry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
diff --git a/java/org/apache/jk/core/JkHandler.java b/java/org/apache/jk/core/JkHandler.java
index 939e2ece9..db089315e 100644
--- a/java/org/apache/jk/core/JkHandler.java
+++ b/java/org/apache/jk/core/JkHandler.java
@@ -25,7 +25,7 @@ import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
-import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.modeler.Registry;
/**
*
diff --git a/java/org/apache/jk/server/JkCoyoteHandler.java b/java/org/apache/jk/server/JkCoyoteHandler.java
index 045d964c8..91a1cda84 100644
--- a/java/org/apache/jk/server/JkCoyoteHandler.java
+++ b/java/org/apache/jk/server/JkCoyoteHandler.java
@@ -22,7 +22,6 @@ import java.util.Iterator;
import javax.management.MBeanServer;
import javax.management.ObjectName;
-import org.apache.commons.modeler.Registry;
import org.apache.coyote.Adapter;
import org.apache.coyote.ProtocolHandler;
import org.apache.coyote.Request;
@@ -41,6 +40,7 @@ import org.apache.tomcat.util.buf.C2BConverter;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.HttpMessages;
import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.net.SSLSupport;
/** Plugs Jk into Coyote. Must be named "type=JkHandler,name=container"
diff --git a/java/org/apache/jk/server/JkMain.java b/java/org/apache/jk/server/JkMain.java
index 1ac6385e6..bd4478259 100644
--- a/java/org/apache/jk/server/JkMain.java
+++ b/java/org/apache/jk/server/JkMain.java
@@ -31,10 +31,10 @@ import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
-import org.apache.commons.modeler.Registry;
import org.apache.jk.core.JkHandler;
import org.apache.jk.core.WorkerEnv;
import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.modeler.Registry;
/** Main class used to startup and configure jk. It manages the conf/jk2.properties file
* and is the target of JMX proxy.
diff --git a/java/org/apache/tomcat/util/DomUtil.java b/java/org/apache/tomcat/util/DomUtil.java
new file mode 100644
index 000000000..3cac8a706
--- /dev/null
+++ b/java/org/apache/tomcat/util/DomUtil.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Few simple utils to read DOM
+ *
+ * @author Costin Manolache
+ */
+public class DomUtil {
+ private static org.apache.commons.logging.Log log=
+ org.apache.commons.logging.LogFactory.getLog( DomUtil.class );
+
+ // -------------------- DOM utils --------------------
+
+ /** Get the trimed text content of a node or null if there is no text
+ */
+ public static String getContent(Node n ) {
+ if( n==null ) return null;
+ Node n1=DomUtil.getChild(n, Node.TEXT_NODE);
+
+ if( n1==null ) return null;
+
+ String s1=n1.getNodeValue();
+ return s1.trim();
+ }
+
+ /** Get the first element child.
+ * @param parent lookup direct childs
+ * @param name name of the element. If null return the first element.
+ */
+ public static Node getChild( Node parent, String name ) {
+ if( parent==null ) return null;
+ Node first=parent.getFirstChild();
+ if( first==null ) return null;
+
+ for (Node node = first; node != null;
+ node = node.getNextSibling()) {
+ //System.out.println("getNode: " + name + " " + node.getNodeName());
+ if( node.getNodeType()!=Node.ELEMENT_NODE)
+ continue;
+ if( name != null &&
+ name.equals( node.getNodeName() ) ) {
+ return node;
+ }
+ if( name == null ) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ public static String getAttribute(Node element, String attName ) {
+ NamedNodeMap attrs=element.getAttributes();
+ if( attrs==null ) return null;
+ Node attN=attrs.getNamedItem(attName);
+ if( attN==null ) return null;
+ return attN.getNodeValue();
+ }
+
+ public static void setAttribute(Node node, String attName, String val) {
+ NamedNodeMap attributes=node.getAttributes();
+ Node attNode=node.getOwnerDocument().createAttribute(attName);
+ attNode.setNodeValue( val );
+ attributes.setNamedItem(attNode);
+ }
+
+ public static void removeAttribute( Node node, String attName ) {
+ NamedNodeMap attributes=node.getAttributes();
+ attributes.removeNamedItem(attName);
+ }
+
+
+ /** Set or replace the text value
+ */
+ public static void setText(Node node, String val) {
+ Node chld=DomUtil.getChild(node, Node.TEXT_NODE);
+ if( chld == null ) {
+ Node textN=node.getOwnerDocument().createTextNode(val);
+ node.appendChild(textN);
+ return;
+ }
+ // change the value
+ chld.setNodeValue(val);
+ }
+
+ /** Find the first direct child with a given attribute.
+ * @param parent
+ * @param elemName name of the element, or null for any
+ * @param attName attribute we're looking for
+ * @param attVal attribute value or null if we just want any
+ */
+ public static Node findChildWithAtt(Node parent, String elemName,
+ String attName, String attVal) {
+
+ Node child=DomUtil.getChild(parent, Node.ELEMENT_NODE);
+ if( attVal== null ) {
+ while( child!= null &&
+ ( elemName==null || elemName.equals( child.getNodeName())) &&
+ DomUtil.getAttribute(child, attName) != null ) {
+ child=getNext(child, elemName, Node.ELEMENT_NODE );
+ }
+ } else {
+ while( child!= null &&
+ ( elemName==null || elemName.equals( child.getNodeName())) &&
+ ! attVal.equals( DomUtil.getAttribute(child, attName)) ) {
+ child=getNext(child, elemName, Node.ELEMENT_NODE );
+ }
+ }
+ return child;
+ }
+
+
+ /** Get the first child's content ( ie it's included TEXT node ).
+ */
+ public static String getChildContent( Node parent, String name ) {
+ Node first=parent.getFirstChild();
+ if( first==null ) return null;
+ for (Node node = first; node != null;
+ node = node.getNextSibling()) {
+ //System.out.println("getNode: " + name + " " + node.getNodeName());
+ if( name.equals( node.getNodeName() ) ) {
+ return getContent( node );
+ }
+ }
+ return null;
+ }
+
+ /** Get the first direct child with a given type
+ */
+ public static Node getChild( Node parent, int type ) {
+ Node n=parent.getFirstChild();
+ while( n!=null && type != n.getNodeType() ) {
+ n=n.getNextSibling();
+ }
+ if( n==null ) return null;
+ return n;
+ }
+
+ /** Get the next sibling with the same name and type
+ */
+ public static Node getNext( Node current ) {
+ String name=current.getNodeName();
+ int type=current.getNodeType();
+ return getNext( current, name, type);
+ }
+
+ /** Return the next sibling with a given name and type
+ */
+ public static Node getNext( Node current, String name, int type) {
+ Node first=current.getNextSibling();
+ if( first==null ) return null;
+
+ for (Node node = first; node != null;
+ node = node.getNextSibling()) {
+
+ if( type >= 0 && node.getNodeType() != type ) continue;
+ //System.out.println("getNode: " + name + " " + node.getNodeName());
+ if( name==null )
+ return node;
+ if( name.equals( node.getNodeName() ) ) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ public static class NullResolver implements EntityResolver {
+ public InputSource resolveEntity (String publicId,
+ String systemId)
+ throws SAXException, IOException
+ {
+ if( log.isTraceEnabled())
+ log.trace("ResolveEntity: " + publicId + " " + systemId);
+ return new InputSource(new StringReader(""));
+ }
+ }
+
+ public static void setAttributes( Object o, Node parent)
+ {
+ NamedNodeMap attrs=parent.getAttributes();
+ if( attrs==null ) return;
+
+ for (int i=0; i Implementation of Test whether notification enabled for this event.
+ * Return true if: Basic implementation of the This can be used directly to wrap an existing java bean, or inside
+ * an mlet or anywhere an MBean would be used. The String parameter
+ * passed to the constructor will be used to construct an instance of the
+ * real object that we wrap.
+ *
+ * Limitations:
+ * IMPLEMENTATION NOTE - 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. IMPLEMENTATION NOTE - This implementation does
+ * not support persistence. IMPLEMENTATION NOTE - This implementation does
+ * not support persistence. IMPLEMENTATION NOTE - This implementation
+ * does not check anything, but this method can be overridden
+ * as required. Implementation of Attribute
+ * descriptor.ModelMBeanAttributeInfo object that corresponds
+ * to this AttributeInfo instance.
+ */
+ protected transient ModelMBeanAttributeInfo info = null;
+ protected String displayName = null;
+ protected String getMethod = null;
+ protected String setMethod = null;
+
+ protected transient Method getMethodObj = null;
+ protected transient Method setMethodObj = null;
+
+ protected boolean readable = true;
+ protected boolean writeable = true;
+
+ protected boolean is = false;
+ protected String type = null;
+
+ protected String persist;
+ protected String defaultStringValue;
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * Override the description property setter.
+ *
+ * @param description The new description
+ */
+ public void setDescription(String description) {
+ super.setDescription(description);
+ this.info = null;
+ }
+
+ /**
+ * Override the name property setter.
+ *
+ * @param name The new name
+ */
+ public void setName(String name) {
+ super.setName(name);
+ this.info = null;
+ }
+
+ /**
+ * The display name of this attribute.
+ */
+ public String getDisplayName() {
+ return (this.displayName);
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ /**
+ * The name of the property getter method, if non-standard.
+ */
+ public String getGetMethod() {
+ return (this.getMethod);
+ }
+
+ public void setGetMethod(String getMethod) {
+ this.getMethod = getMethod;
+ this.info = null;
+ }
+
+ public Method getGetMethodObj() {
+ return getMethodObj;
+ }
+
+ public void setGetMethodObj(Method getMethodObj) {
+ this.getMethodObj = getMethodObj;
+ }
+
+ public Method getSetMethodObj() {
+ return setMethodObj;
+ }
+
+ public void setSetMethodObj(Method setMethodObj) {
+ this.setMethodObj = setMethodObj;
+ }
+
+ /**
+ * Is this a boolean attribute with an "is" getter?
+ */
+ public boolean isIs() {
+ return (this.is);
+ }
+
+ public void setIs(boolean is) {
+ this.is = is;
+ this.info = null;
+ }
+
+
+ /**
+ * Is this attribute readable by management applications?
+ */
+ public boolean isReadable() {
+ return (this.readable);
+ }
+
+ public void setReadable(boolean readable) {
+ this.readable = readable;
+ this.info = null;
+ }
+
+
+ /**
+ * The name of the property setter method, if non-standard.
+ */
+ public String getSetMethod() {
+ return (this.setMethod);
+ }
+
+ public void setSetMethod(String setMethod) {
+ this.setMethod = setMethod;
+ this.info = null;
+ }
+
+
+ /**
+ * The fully qualified Java class name of this attribute.
+ */
+ public String getType() {
+ return (this.type);
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ this.info = null;
+ }
+
+
+ /**
+ * Is this attribute writeable by management applications?
+ */
+ public boolean isWriteable() {
+ return (this.writeable);
+ }
+
+ public void setWriteable(boolean writeable) {
+ this.writeable = writeable;
+ this.info = null;
+ }
+
+ /** Persistence policy.
+ * All persistent attributes should have this attribute set.
+ * Valid values:
+ * ???
+ */
+ public String getPersist() {
+ return persist;
+ }
+
+ public void setPersist(String persist) {
+ this.persist = persist;
+ }
+
+ /** Default value. If set, it can provide info to the user and
+ * it can be used by persistence mechanism to generate a more compact
+ * representation ( a value may not be saved if it's default )
+ */
+ public String getDefault() {
+ return defaultStringValue;
+ }
+
+ public void setDefault(String defaultStringValue) {
+ this.defaultStringValue = defaultStringValue;
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Create and return a ModelMBeanAttributeInfo object that
+ * corresponds to the attribute described by this instance.
+ */
+ public ModelMBeanAttributeInfo createAttributeInfo() {
+ // Return our cached information (if any)
+ if (info != null)
+ return (info);
+ if((getMethodObj != null) || (setMethodObj != null) ) {
+ try {
+ info=new ModelMBeanAttributeInfo(getName(), getDescription(),
+ getMethodObj, setMethodObj);
+ return info;
+ } catch( Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ // Create and return a new information object
+ info = new ModelMBeanAttributeInfo
+ (getName(), getType(), getDescription(),
+ isReadable(), isWriteable(), false);
+ Descriptor descriptor = info.getDescriptor();
+ if (getDisplayName() != null)
+ descriptor.setField("displayName", getDisplayName());
+ if (isReadable()) {
+ if (getGetMethod() != null)
+ descriptor.setField("getMethod", getGetMethod());
+ else
+ descriptor.setField("getMethod",
+ getMethodName(getName(), true, isIs()));
+ }
+ if (isWriteable()) {
+ if (getSetMethod() != null)
+ descriptor.setField("setMethod", getSetMethod());
+ else
+ descriptor.setField("setMethod",
+ getMethodName(getName(), false, false));
+ }
+ addFields(descriptor);
+ info.setDescriptor(descriptor);
+ return (info);
+
+ }
+
+
+ /**
+ * Return a string representation of this attribute descriptor.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("AttributeInfo[");
+ sb.append("name=");
+ sb.append(name);
+ sb.append(", description=");
+ sb.append(description);
+ if (!readable) {
+ sb.append(", readable=");
+ sb.append(readable);
+ }
+ sb.append(", type=");
+ sb.append(type);
+ if (!writeable) {
+ sb.append(", writeable=");
+ sb.append(writeable);
+ }
+ sb.append("]");
+ return (sb.toString());
+
+ }
+
+
+ // -------------------------------------------------------- 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?
+ */
+ private String getMethodName(String name, boolean getter, boolean is) {
+
+ StringBuffer sb = new StringBuffer();
+ 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());
+
+ }
+
+
+}
diff --git a/java/org/apache/tomcat/util/modeler/BaseAttributeFilter.java b/java/org/apache/tomcat/util/modeler/BaseAttributeFilter.java
new file mode 100644
index 000000000..0701f6c70
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/BaseAttributeFilter.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+
+/**
+ * NotificationFilter for attribute change
+ * notifications. This class is used by BaseModelMBean to
+ * construct attribute change notification event filters when a filter is not
+ * supplied by the application.null 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 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.
+ */
+ public String[] getNames() {
+
+ synchronized (names) {
+ return ((String[]) names.toArray(new String[names.size()]));
+ }
+
+ }
+
+
+ /**
+ *
+ *
+ */
+ 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);
+ }
+
+ }
+
+
+}
diff --git a/java/org/apache/tomcat/util/modeler/BaseModelMBean.java b/java/org/apache/tomcat/util/modeler/BaseModelMBean.java
new file mode 100644
index 000000000..f633beb1c
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/BaseModelMBean.java
@@ -0,0 +1,1416 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed 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.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.management.Attribute;
+import javax.management.AttributeChangeNotification;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.Descriptor;
+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.ServiceNotFoundException;
+import javax.management.modelmbean.DescriptorSupport;
+import javax.management.modelmbean.InvalidTargetObjectTypeException;
+import javax.management.modelmbean.ModelMBean;
+import javax.management.modelmbean.ModelMBeanAttributeInfo;
+import javax.management.modelmbean.ModelMBeanInfo;
+import javax.management.modelmbean.ModelMBeanInfoSupport;
+import javax.management.modelmbean.ModelMBeanNotificationInfo;
+import javax.management.modelmbean.ModelMBeanOperationInfo;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.modeler.modules.ModelerSource;
+
+// TODO: enable ant-like substitutions ? ( or at least discuss it )
+
+/**
+ * ModelMBean interface, which
+ * supports the minimal requirements of the interface contract.
+ *
+ *
+ * @author Craig R. McClanahan
+ * @author Costin Manolache
+ * @version $Revision: 383269 $ $Date: 2006-03-05 03:22:41 +0100 (dim., 05 mars 2006) $
+ */
+
+public class BaseModelMBean implements ModelMBean, MBeanRegistration {
+ private static Log log = LogFactory.getLog(BaseModelMBean.class);
+
+ // ----------------------------------------------------------- Constructors
+
+ /**
+ * Construct a objectReference are
+ * supportd.invoke() are immediately executed.
+ *
+ * void.ModelMBean with default
+ * ModelMBeanInfo information.
+ *
+ * @exception MBeanException if the initializer of an object
+ * throws an exception
+ * @exception RuntimeOperationsException if an IllegalArgumentException
+ * occurs
+ */
+ public BaseModelMBean() throws MBeanException, RuntimeOperationsException {
+
+ super();
+ if( log.isDebugEnabled()) log.debug("default constructor");
+ setModelMBeanInfo(createDefaultModelMBeanInfo());
+ }
+
+
+ /**
+ * Construct a ModelMBean associated with the specified
+ * ModelMBeanInfo information.
+ *
+ * @param info ModelMBeanInfo for this MBean
+ *
+ * @exception MBeanException if the initializer of an object
+ * throws an exception
+ * @exception RuntimeOperationsException if an IllegalArgumentException
+ * occurs
+ */
+ public BaseModelMBean(ModelMBeanInfo info)
+ throws MBeanException, RuntimeOperationsException {
+ // XXX should be deprecated - just call setInfo
+ super();
+ setModelMBeanInfo(info);
+ if( log.isDebugEnabled()) log.debug("ModelMBeanInfo constructor");
+ }
+
+ /** Construct a ModelMBean of a specified type.
+ * The type can be a class name or the key used in one of the descriptors.
+ *
+ * If no descriptor is available, we'll first try to locate one in
+ * the same package with the class, then use introspection.
+ *
+ * The mbean resource will be created.
+ *
+ * @param type Class name or the type key used in the descriptor.
+ * @throws MBeanException
+ * @throws RuntimeOperationsException
+ */
+ public BaseModelMBean( String type )
+ throws MBeanException, RuntimeOperationsException
+ {
+ try {
+ // This constructor is used from ModelMBeanInfo object that controls our activity.
+ */
+ protected ModelMBeanInfo info = null;
+
+
+ /**
+ * The managed resource this MBean is associated with (if any).
+ */
+ protected Object resource = null;
+ protected String resourceType = null;
+
+ /** Source object used to read this mbean. Can be used to
+ * persist the mbean
+ */
+ protected ModelerSource source=null;
+
+ /** Attribute values. XXX That can be stored in the value Field
+ */
+ protected HashMap attributes=new HashMap();
+
+ // --------------------------------------------------- DynamicMBean Methods
+ static final Object[] NO_ARGS_PARAM=new Object[0];
+ static final Class[] NO_ARGS_PARAM_SIG=new Class[0];
+ // key: attribute val: getter method
+ private Hashtable getAttMap=new Hashtable();
+
+ // key: attribute val: setter method
+ private Hashtable setAttMap=new Hashtable();
+
+ // 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
+ */
+ 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);
+ }
+
+ // Extract the method from cache
+ Method m=(Method)getAttMap.get( name );
+
+ if( m==null ) {
+ // Look up the actual operation to be used
+ ModelMBeanAttributeInfo attrInfo = info.getAttribute(name);
+ if (attrInfo == null)
+ throw new AttributeNotFoundException(" Cannot find attribute " + name);
+ Descriptor attrDesc = attrInfo.getDescriptor();
+ if (attrDesc == null)
+ throw new AttributeNotFoundException("Cannot find attribute " + name + " descriptor");
+ String getMethod = (String) attrDesc.getFieldValue("getMethod");
+
+ if (getMethod == null)
+ throw new AttributeNotFoundException("Cannot find attribute " + name + " get method name");
+
+ Object object = null;
+ NoSuchMethodException exception = null;
+ try {
+ object = this;
+ 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);
+ getAttMap.put( name, m );
+ }
+
+ 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
+ */
+ 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);
+
+ }
+
+
+ /**
+ * Return the MBeanInfo object for this MBean.
+ */
+ public MBeanInfo getMBeanInfo() {
+ // XXX Why do we have to clone ?
+ if( info== null ) return null;
+ return ((MBeanInfo) info.clone());
+ }
+
+
+ /**
+ * Invoke a particular method on this MBean, and return any returned
+ * value.
+ *
+ * null 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.
+ *
+ * This method will detect and call "setModelMbean" method. A resource
+ * can implement this method to get a reference to the model mbean.
+ * The reference can be used to send notification and access the
+ * registry.
+ *
+ * @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 InvalidTargetObjectTypeException if this ModelMBean is
+ * asked to handle a reference type it cannot deal with
+ * @exception MBeanException if the initializer of the object throws
+ * an exception
+ * @exception RuntimeOperationsException if the managed resource or the
+ * resource type is null or invalid
+ */
+ public void setManagedResource(Object resource, String type)
+ throws InstanceNotFoundException, InvalidTargetObjectTypeException,
+ 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 );
+ }
+ }
+
+
+ /**
+ * Initialize the ModelMBeanInfo associated with this
+ * ModelMBean. After the information and associated
+ * descriptors have been customized, the ModelMBean should
+ * be registered with the associated MBeanServer.
+ *
+ * Currently the model can be set after registration. This behavior is
+ * deprecated and won't be supported in future versions.
+ *
+ * @param info The ModelMBeanInfo object to be used by this ModelMBean
+ *
+ * @exception MBeanException If an exception occurs recording this
+ * ModelMBeanInfo information
+ * @exception RuntimeOperations if the specified parameter is
+ * null or invalid
+ */
+ public void setModelMBeanInfo(ModelMBeanInfo info)
+ throws MBeanException, RuntimeOperationsException {
+
+ if (info == null)
+ throw new RuntimeOperationsException
+ (new IllegalArgumentException("ModelMBeanInfo is null"),
+ "ModelMBeanInfo is null");
+
+ if (!isModelMBeanInfoValid(info))
+ throw new RuntimeOperationsException
+ (new IllegalArgumentException("ModelMBeanInfo is invalid"),
+ "ModelMBeanInfo is invalid");
+
+ this.info = (ModelMBeanInfo) info.clone();
+
+ }
+
+
+ // ------------------------------ 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 null
+ * 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
+ */
+ 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
+ */
+ public void removeAttributeChangeNotificationListener
+ (NotificationListener listener, String name)
+ throws ListenerNotFoundException {
+
+ if (listener == null)
+ throw new IllegalArgumentException("Listener is null");
+ if (attributeBroadcaster == null)
+ attributeBroadcaster = new BaseNotificationBroadcaster();
+
+ // FIXME - currently this removes *all* notifications for this listener
+ attributeBroadcaster.removeNotificationListener(listener);
+
+ }
+
+
+ /**
+ * Remove an attribute change notification event listener from
+ * this MBean.
+ *
+ * @param listener The listener to be removed
+ * @param attributeName The attribute name for which no more events are required
+ * @param handback Handback object to be sent along with event
+ * notifications
+ *
+ *
+ * @exception ListenerNotFoundException if this listener is not
+ * registered in the MBean
+ */
+ public void removeAttributeChangeNotificationListener
+ (NotificationListener listener, String attributeName, Object handback)
+ throws ListenerNotFoundException {
+
+ removeAttributeChangeNotificationListener(listener, attributeName);
+
+ }
+
+
+ /**
+ * Send an AttributeChangeNotification to all registered
+ * listeners.
+ *
+ * @param notification The AttributeChangeNotification
+ * that will be passed
+ *
+ * @exception MBeanException if an object initializer throws an
+ * exception
+ * @exception RuntimeOperationsException wraps IllegalArgumentException
+ * when the specified notification is null or invalid
+ */
+ 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 AttributeChangeNotification to all registered
+ * listeners.
+ *
+ * @param oldValue The original value of the Attribute
+ * @param newValue The new value of the Attribute
+ *
+ * @exception MBeanException if an object initializer throws an
+ * exception
+ * @exception RuntimeOperationsException wraps IllegalArgumentException
+ * when the specified notification is null or invalid
+ */
+ 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 Notification to all registered listeners as a
+ * jmx.modelmbean.general notification.
+ *
+ * @param notification The Notification that will be passed
+ *
+ * @exception MBeanException if an object initializer throws an
+ * exception
+ * @exception RuntimeOperationsException wraps IllegalArgumentException
+ * when the specified notification is null or invalid
+ */
+ 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 Notification which contains the specified string
+ * as a jmx.modelmbean.generic 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 null or invalid
+ */
+ 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 null for no filtering
+ * @param handback Handback object to be sent along with event
+ * notifications
+ *
+ * @exception IllegalArgumentException if the listener parameter is null
+ */
+ 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 MBeanNotificationInfo object describing the
+ * notifications sent by this MBean.
+ */
+ public MBeanNotificationInfo[] getNotificationInfo() {
+
+ // Acquire the set of application notifications
+ MBeanNotificationInfo current[] = info.getNotifications();
+ if (current == null)
+ current = new MBeanNotificationInfo[0];
+ 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 ModelMBeanNotificationInfo
+ (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 ModelMBeanNotificationInfo
+ (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
+ */
+ public void removeNotificationListener(NotificationListener listener)
+ throws ListenerNotFoundException {
+
+ if (listener == null)
+ throw new IllegalArgumentException("Listener is null");
+ if (generalBroadcaster == null)
+ generalBroadcaster = new BaseNotificationBroadcaster();
+ generalBroadcaster.removeNotificationListener(listener);
+
+
+ }
+
+
+ /**
+ * 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)
+ * @param handback Handback object to be sent along with event
+ * notifications
+ *
+ * @exception ListenerNotFoundException if this listener is not
+ * registered in the MBean
+ */
+ public void removeNotificationListener(NotificationListener listener,
+ Object handback)
+ throws ListenerNotFoundException {
+
+ removeNotificationListener(listener);
+
+ }
+
+
+ /**
+ * 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)
+ * @param filter Filter object used to filter event notifications
+ * actually delivered, or null for no filtering
+ * @param handback Handback object to be sent along with event
+ * notifications
+ *
+ * @exception ListenerNotFoundException if this listener is not
+ * registered in the MBean
+ */
+ public void removeNotificationListener(NotificationListener listener,
+ NotificationFilter filter,
+ Object handback)
+ throws ListenerNotFoundException {
+
+ removeNotificationListener(listener);
+
+ }
+
+
+ // ------------------------------------------------ PersistentMBean Methods
+
+
+ /**
+ * Instantiates this MBean instance from data found in the persistent
+ * store. The data loaded could include attribute and operation values.
+ * This method should be called during construction or initialization
+ * of the instance, and before the MBean is registered with the
+ * MBeanServer.
+ *
+ * ModelMBeanInfo object.
+ */
+ protected ModelMBeanInfo createDefaultModelMBeanInfo() {
+
+ return (new ModelMBeanInfoSupport(this.getClass().getName(),
+ "Default ModelMBean",
+ null, null, null, null));
+
+ }
+
+ /**
+ * Is the specified ModelMBeanInfo instance valid?
+ *
+ * ModelMBeanInfo object to check
+ */
+ protected boolean isModelMBeanInfoValid(ModelMBeanInfo info) {
+ return (true);
+ }
+
+ // -------------------- Registration --------------------
+ // XXX We can add some method patterns here- like setName() and
+ // setDomain() for code that doesn't implement the Registration
+
+ 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;
+ }
+
+ public void postRegister(Boolean registrationDone) {
+ if( resource instanceof MBeanRegistration ) {
+ ((MBeanRegistration)resource).postRegister(registrationDone);
+ }
+ }
+
+ public void preDeregister() throws Exception {
+ if( resource instanceof MBeanRegistration ) {
+ ((MBeanRegistration)resource).preDeregister();
+ }
+ }
+
+ public void postDeregister() {
+ if( resource instanceof MBeanRegistration ) {
+ ((MBeanRegistration)resource).postDeregister();
+ }
+ }
+
+ static class MethodKey {
+ private String name;
+ private String[] signature;
+
+ MethodKey(String name, String[] signature) {
+ this.name = name;
+ if(signature == null) {
+ signature = new String[0];
+ }
+ this.signature = signature;
+ }
+
+ public boolean equals(Object other) {
+ if(!(other instanceof MethodKey)) {
+ return false;
+ }
+ MethodKey omk = (MethodKey)other;
+ if(!name.equals(omk.name)) {
+ return false;
+ }
+ if(signature.length != omk.signature.length) {
+ return false;
+ }
+ for(int i=0; i < signature.length; i++) {
+ if(!signature[i].equals(omk.signature[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public int hashCode() {
+ return name.hashCode();
+ }
+ }
+}
diff --git a/java/org/apache/tomcat/util/modeler/BaseNotification.java b/java/org/apache/tomcat/util/modeler/BaseNotification.java
new file mode 100644
index 000000000..d6a5e2715
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/BaseNotification.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.Notification;
+
+
+/**
+ * Base JMX Notification. Supports in int code and notes - for faster
+ * access and dispatching.
+ *
+ * @author Costin Manolache
+ */
+public final class BaseNotification extends Notification {
+
+ // ----------------------------------------------------------- Constructors
+ private int code;
+ private String type;
+ private Object source;
+ private long seq;
+ private long tstamp;
+
+ /**
+ * Private constructor.
+ */
+ private BaseNotification(String type,
+ Object source,
+ long seq,
+ long tstamp,
+ int code) {
+ super(type, source, seq, tstamp);
+ init( type, source, seq, tstamp, code );
+ this.code=code;
+ }
+
+ public void recycle() {
+
+ }
+
+ public void init( String type, Object source,
+ long seq, long tstamp, int code )
+ {
+ this.type=type;
+ this.source = source;
+ this.seq=seq;
+ this.tstamp=tstamp;
+ this.code = code;
+ }
+
+ // -------------------- Override base methods --------------------
+ // All base methods need to be overriden - in order to support recycling.
+
+
+ // -------------------- Information associated with the notification ----
+ // Like events ( which Notification extends ), notifications may store
+ // informations related with the event that trigered it. Source and type is
+ // one piece, but it is common to store more info.
+
+ /** Action id, useable in switches and table indexes
+ */
+ public int getCode() {
+ return code;
+ }
+
+ // XXX Make it customizable - or grow it
+ private Object notes[]=new Object[32];
+
+ public final Object getNote(int i ) {
+ return notes[i];
+ }
+
+ public final void setNote(int i, Object o ) {
+ notes[i]=o;
+ }
+}
diff --git a/java/org/apache/tomcat/util/modeler/BaseNotificationBroadcaster.java b/java/org/apache/tomcat/util/modeler/BaseNotificationBroadcaster.java
new file mode 100644
index 000000000..197b9e69a
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/BaseNotificationBroadcaster.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+
+/**
+ * NotificationBroadcaster for attribute
+ * change notifications. This class is used by BaseModelMBean to
+ * handle notifications of attribute change events to interested listeners.
+ *BaseNotificationBroadcasterEntry
+ * entries.
+ */
+ protected ArrayList 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 null for no filtering
+ * @param handback Handback object to be sent along with event
+ * notifications
+ *
+ * @exception IllegalArgumentException if the listener parameter is null
+ */
+ 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;
+ Iterator items = entries.iterator();
+ while (items.hasNext()) {
+ BaseNotificationBroadcasterEntry item =
+ (BaseNotificationBroadcasterEntry) items.next();
+ 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 MBeanNotificationInfo object describing the
+ * notifications sent by this MBean.
+ */
+ 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
+ */
+ public void removeNotificationListener(NotificationListener listener)
+ throws ListenerNotFoundException {
+
+ synchronized (entries) {
+ Iterator items = entries.iterator();
+ while (items.hasNext()) {
+ BaseNotificationBroadcasterEntry item =
+ (BaseNotificationBroadcasterEntry) items.next();
+ if (item.listener == listener)
+ items.remove();
+ }
+ }
+
+ }
+
+
+ /**
+ * 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)
+ * @param handback Handback object to be sent along with event
+ * notifications
+ *
+ * @exception ListenerNotFoundException if this listener is not
+ * registered in the MBean
+ */
+ public void removeNotificationListener(NotificationListener listener,
+ Object handback)
+ throws ListenerNotFoundException {
+
+ removeNotificationListener(listener);
+
+ }
+
+
+ /**
+ * 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)
+ * @param filter Filter object used to filter event notifications
+ * actually delivered, or null for no filtering
+ * @param handback Handback object to be sent along with event
+ * notifications
+ *
+ * @exception ListenerNotFoundException if this listener is not
+ * registered in the MBean
+ */
+ public void removeNotificationListener(NotificationListener listener,
+ NotificationFilter filter,
+ Object handback)
+ throws ListenerNotFoundException {
+
+ removeNotificationListener(listener);
+
+ }
+
+
+ /**
+ * Send the specified notification to all interested listeners.
+ *
+ * @param notification The notification to be sent
+ */
+ public void sendNotification(Notification notification) {
+
+ synchronized (entries) {
+ Iterator items = entries.iterator();
+ while (items.hasNext()) {
+ BaseNotificationBroadcasterEntry item =
+ (BaseNotificationBroadcasterEntry) items.next();
+ if ((item.filter != null) &&
+ (!item.filter.isNotificationEnabled(notification)))
+ continue;
+ item.listener.handleNotification(notification, item.handback);
+ }
+ }
+
+ }
+
+
+ // -------------------- Internal Extensions --------------------
+
+ // Fast access. First index is the hook type
+ // ( FixedNotificationFilter.getType() ).
+ NotificationListener hooks[][]=new NotificationListener[20][];
+ int hookCount[]=new int[20];
+
+ private synchronized void registerNotifications( FixedNotificationFilter filter ) {
+ String names[]=filter.getNames();
+ Registry reg=Registry.getRegistry();
+ for( int i=0; iConstructor
+ * descriptor.
ModelMBeanConstructorInfo object that corresponds
+ * to this ConstructorInfo instance.
+ */
+ transient ModelMBeanConstructorInfo info = null;
+ protected String displayName = null;
+ protected ParameterInfo parameters[] = new ParameterInfo[0];
+
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * Override the description property setter.
+ *
+ * @param description The new description
+ */
+ public void setDescription(String description) {
+ super.setDescription(description);
+ this.info = null;
+ }
+
+
+ /**
+ * Override the name property setter.
+ *
+ * @param name The new name
+ */
+ public void setName(String name) {
+ super.setName(name);
+ this.info = null;
+ }
+
+
+ /**
+ * The display name of this attribute.
+ */
+ public String getDisplayName() {
+ return (this.displayName);
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+
+ /**
+ * The set of parameters for this constructor.
+ */
+ public ParameterInfo[] getSignature() {
+ return (this.parameters);
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Add a new parameter to the set of parameters for this constructor.
+ *
+ * @param parameter The new parameter descriptor
+ */
+ public void addParameter(ParameterInfo parameter) {
+
+ synchronized (parameters) {
+ ParameterInfo results[] = new ParameterInfo[parameters.length + 1];
+ System.arraycopy(parameters, 0, results, 0, parameters.length);
+ results[parameters.length] = parameter;
+ parameters = results;
+ this.info = null;
+ }
+
+ }
+
+
+ /**
+ * Create and return a ModelMBeanConstructorInfo object that
+ * corresponds to the attribute described by this instance.
+ */
+ public ModelMBeanConstructorInfo createConstructorInfo() {
+
+ // Return our cached information (if any)
+ if (info != null)
+ return (info);
+
+ // Create and return a new information object
+ ParameterInfo params[] = getSignature();
+ MBeanParameterInfo parameters[] =
+ new MBeanParameterInfo[params.length];
+ for (int i = 0; i < params.length; i++)
+ parameters[i] = params[i].createParameterInfo();
+ info = new ModelMBeanConstructorInfo
+ (getName(), getDescription(), parameters);
+ Descriptor descriptor = info.getDescriptor();
+ descriptor.removeField("class");
+ if (getDisplayName() != null)
+ descriptor.setField("displayName", getDisplayName());
+ addFields(descriptor);
+ info.setDescriptor(descriptor);
+ return (info);
+
+ }
+
+
+ /**
+ * Return a string representation of this constructor descriptor.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("ConstructorInfo[");
+ sb.append("name=");
+ sb.append(name);
+ sb.append(", description=");
+ sb.append(description);
+ sb.append(", parameters=");
+ sb.append(parameters.length);
+ sb.append("]");
+ return (sb.toString());
+
+ }
+
+
+}
diff --git a/java/org/apache/tomcat/util/modeler/FeatureInfo.java b/java/org/apache/tomcat/util/modeler/FeatureInfo.java
new file mode 100644
index 000000000..c23d96c7d
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/FeatureInfo.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed 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 java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.management.Descriptor;
+
+
+/**
+ * Convenience base class for AttributeInfo,
+ * ConstructorInfo, and OperationInfo classes
+ * that will be used to collect configuration information for the
+ * ModelMBean beans exposed for management.
Add a new field to the fields associated with the + * Descriptor that will be created from this metadata.
+ * + * @param field The field to be added + */ + public void addField(FieldInfo field) { + fields.add(field); + } + + + // ------------------------------------------------------ Protected Methods + + + /** + *Add the name/value fields that have been stored into the
+ * specified Descriptor instance.
Descriptor to add fields to
+ */
+ protected void addFields(Descriptor descriptor) {
+
+ Iterator items = getFields().iterator();
+ while (items.hasNext()) {
+ FieldInfo item = (FieldInfo) items.next();
+ descriptor.setField(item.getName(), item.getValue());
+ }
+
+ }
+
+
+}
diff --git a/java/org/apache/tomcat/util/modeler/FieldInfo.java b/java/org/apache/tomcat/util/modeler/FieldInfo.java
new file mode 100644
index 000000000..ddc6a3c82
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/FieldInfo.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+
+/**
+ * Simple JavaBean representing the contents of a <field>
+ * element in an MBeans descriptor file.
+ */
+
+public class FieldInfo implements Serializable {
+ static final long serialVersionUID = -8226401620640873691L;
+
+ /**
+ *
The field name for this field of a descriptor.
+ */ + protected String name = null; + + public String getName() { + return (this.name); + } + + public void setName(String name) { + this.name = name; + } + + + /** + *The field value for this field of a descriptor.
+ */ + protected Object value = null; + + public Object getValue() { + return (this.value); + } + + public void setValue(Object value) { + this.value = value; + } + + +} diff --git a/java/org/apache/tomcat/util/modeler/FixedNotificationFilter.java b/java/org/apache/tomcat/util/modeler/FixedNotificationFilter.java new file mode 100644 index 000000000..6fb1836c4 --- /dev/null +++ b/java/org/apache/tomcat/util/modeler/FixedNotificationFilter.java @@ -0,0 +1,94 @@ +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed 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.Notification; +import javax.management.NotificationFilter; + + +/** + * Special NotificationFilter that allows modeler to optimize its notifications. + * + * This class is immutable - after you construct it it'll filter based on + * a fixed set of notification names. + * + * The JMX specification requires the filters to be called before the + * notifications are sent. We can call this filter well in advance, when + * the listener is added. Based on the result we can maintain separate + * channels for each notification - and reduce the overhead. + * + * @author Costin Manolache + */ +public class FixedNotificationFilter implements NotificationFilter { + + /** + * The set of attribute names that are accepted by this filter. If this + * list is empty, all attribute names are accepted. + */ + private HashSet names = new HashSet(); + String namesA[]=null; + + /** + * Construct a new filter that accepts only the specified notification + * names. + * + * @param names Names of the notification types + */ + public FixedNotificationFilter(String names[]) { + super(); + } + + /** + * 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. + */ + public String[] getNames() { + synchronized (names) { + return ((String[]) names.toArray(new String[names.size()])); + } + } + + + /** + *Test whether notification enabled for this event. + * Return true if:
+ *Internal configuration information for a managed bean (MBean) + * descriptor.
+ * + * @author Craig R. McClanahan + * @version $Revision: 383268 $ $Date: 2006-03-05 03:02:01 +0100 (dim., 05 mars 2006) $ + */ + +public class ManagedBean implements java.io.Serializable +{ + // ----------------------------------------------------- Instance Variables + + + /** + * TheModelMBeanInfo object that corresponds
+ * to this ManagedBean instance.
+ */
+ transient ModelMBeanInfo info = null;
+ protected AttributeInfo attributes[] = new AttributeInfo[0];
+ protected String className =
+ "org.apache.tomcat.util.modeler.BaseModelMBean";
+ protected ConstructorInfo constructors[] = new ConstructorInfo[0];
+ protected String description = null;
+ protected String domain = null;
+ protected String group = null;
+ protected String name = null;
+
+ protected List fields = new ArrayList();
+ protected NotificationInfo notifications[] = new NotificationInfo[0];
+ protected OperationInfo operations[] = new OperationInfo[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
+
+
+ /**
+ * The collection of attributes for this MBean.
+ */
+ public AttributeInfo[] getAttributes() {
+ return (this.attributes);
+ }
+
+
+ /**
+ * The fully qualified name of the Java class of the MBean
+ * described by this descriptor. If not specified, the standard JMX
+ * class (javax.management.modelmbean.RequiredModeLMBean)
+ * will be utilized.
+ */
+ public String getClassName() {
+ return (this.className);
+ }
+
+ public void setClassName(String className) {
+ this.className = className;
+ this.info = null;
+ }
+
+
+ /**
+ * The collection of constructors for this MBean.
+ */
+ public ConstructorInfo[] getConstructors() {
+ return (this.constructors);
+ }
+
+
+ /**
+ * The human-readable description of this MBean.
+ */
+ public String getDescription() {
+ return (this.description);
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ this.info = null;
+ }
+
+
+ /**
+ * The (optional) ObjectName 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 a List of the {@link FieldInfo} objects for
+ * the name/value pairs that should be
+ * added to the Descriptor created from this metadata.
Add a new field to the fields associated with the + * Descriptor that will be created from this metadata.
+ * + * @param field The field to be added + */ + public void addField(FieldInfo field) { + fields.add(field); + } + + + /** + * Add a new notification to the set of notifications for this MBean. + * + * @param notification The new notification descriptor + */ + public void addNotification(NotificationInfo notification) { + + synchronized (notifications) { + NotificationInfo results[] = + new NotificationInfo[notifications.length + 1]; + System.arraycopy(notifications, 0, results, 0, + notifications.length); + results[notifications.length] = notification; + notifications = results; + this.info = null; + } + + } + + + /** + * Add a new operation to the set of operations for this MBean. + * + * @param operation The new operation descriptor + */ + public void addOperation(OperationInfo operation) { + synchronized (operations) { + OperationInfo results[] = + new OperationInfo[operations.length + 1]; + System.arraycopy(operations, 0, results, 0, operations.length); + results[operations.length] = operation; + operations = results; + this.info = null; + } + + } + + + /** + * Create and return aModelMBean that has been
+ * preconfigured with the ModelMBeanInfo information
+ * for this managed bean, but is not associated with any particular
+ * managed resource. The returned ModelMBean will
+ * NOT have been registered with our
+ * MBeanServer.
+ *
+ * @exception InstanceNotFoundException if the managed resource
+ * object cannot be found
+ * @exception InvalidTargetObjectTypeException if our MBean cannot
+ * handle object references (should never happen)
+ * @exception MBeanException if a problem occurs instantiating the
+ * ModelMBean instance
+ * @exception RuntimeOperationsException if a JMX runtime error occurs
+ */
+ public ModelMBean createMBean()
+ throws InstanceNotFoundException,
+ InvalidTargetObjectTypeException,
+ MBeanException, RuntimeOperationsException {
+
+ return (createMBean(null));
+
+ }
+
+
+ /**
+ * Create and return a ModelMBean that has been
+ * preconfigured with the ModelMBeanInfo information
+ * for this managed bean, and is associated with the specified
+ * managed object instance. The returned ModelMBean
+ * will NOT have been registered with our
+ * MBeanServer.
+ *
+ * @param instance Instanced of the managed object, or null
+ * for no associated instance
+ *
+ * @exception InstanceNotFoundException if the managed resource
+ * object cannot be found
+ * @exception InvalidTargetObjectTypeException if our MBean cannot
+ * handle object references (should never happen)
+ * @exception MBeanException if a problem occurs instantiating the
+ * ModelMBean instance
+ * @exception RuntimeOperationsException if a JMX runtime error occurs
+ */
+ public ModelMBean createMBean(Object instance)
+ throws InstanceNotFoundException,
+ InvalidTargetObjectTypeException,
+ MBeanException, RuntimeOperationsException {
+
+ // Load the ModelMBean implementation class
+ 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());
+ }
+
+ // Create a new ModelMBean instance
+ ModelMBean mbean = null;
+ try {
+ mbean = (ModelMBean) clazz.newInstance();
+ mbean.setModelMBeanInfo(createMBeanInfo());
+ } catch (MBeanException e) {
+ throw e;
+ } catch (RuntimeOperationsException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new MBeanException
+ (e, "Cannot instantiate ModelMBean of class " +
+ getClassName());
+ }
+
+ // Set the managed resource (if any)
+ try {
+ if (instance != null)
+ mbean.setManagedResource(instance, "ObjectReference");
+ } catch (InstanceNotFoundException e) {
+ throw e;
+ } catch (InvalidTargetObjectTypeException e) {
+ throw e;
+ }
+ return (mbean);
+
+ }
+
+
+ /**
+ * Create and return a ModelMBeanInfo object that
+ * describes this entire managed bean.
+ */
+ public ModelMBeanInfo createMBeanInfo() {
+
+ // Return our cached information (if any)
+ if (info != null)
+ return (info);
+
+ // Create subordinate information descriptors as required
+ AttributeInfo attrs[] = getAttributes();
+ ModelMBeanAttributeInfo attributes[] =
+ new ModelMBeanAttributeInfo[attrs.length];
+ for (int i = 0; i < attrs.length; i++)
+ attributes[i] = attrs[i].createAttributeInfo();
+
+ ConstructorInfo consts[] = getConstructors();
+ ModelMBeanConstructorInfo constructors[] =
+ new ModelMBeanConstructorInfo[consts.length];
+ for (int i = 0; i < consts.length; i++)
+ constructors[i] = consts[i].createConstructorInfo();
+ NotificationInfo notifs[] = getNotifications();
+ ModelMBeanNotificationInfo notifications[] =
+ new ModelMBeanNotificationInfo[notifs.length];
+ for (int i = 0; i < notifs.length; i++)
+ notifications[i] = notifs[i].createNotificationInfo();
+ OperationInfo opers[] = getOperations();
+ ModelMBeanOperationInfo operations[] =
+ new ModelMBeanOperationInfo[opers.length];
+ for (int i = 0; i < opers.length; i++)
+ operations[i] = opers[i].createOperationInfo();
+
+ /*
+ // Add operations for attribute getters and setters as needed
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < operations.length; i++)
+ list.add(operations[i]);
+ for (int i = 0; i < attributes.length; i++) {
+ Descriptor descriptor = attributes[i].getDescriptor();
+ String getMethod = (String) descriptor.getFieldValue("getMethod");
+ if (getMethod != null) {
+ OperationInfo oper =
+ new OperationInfo(getMethod, true,
+ attributes[i].getType());
+ list.add(oper.createOperationInfo());
+ }
+ String setMethod = (String) descriptor.getFieldValue("setMethod");
+ if (setMethod != null) {
+ OperationInfo oper =
+ new OperationInfo(setMethod, false,
+ attributes[i].getType());
+ list.add(oper.createOperationInfo());
+ }
+ }
+ if (list.size() > operations.length)
+ operations =
+ (ModelMBeanOperationInfo[]) list.toArray(operations);
+ */
+
+ // Construct and return a new ModelMBeanInfo object
+ info = new ModelMBeanInfoSupport
+ (getClassName(), getDescription(),
+ attributes, constructors, operations, notifications);
+ try {
+ Descriptor descriptor = info.getMBeanDescriptor();
+ Iterator fields = getFields().iterator();
+ while (fields.hasNext()) {
+ FieldInfo field = (FieldInfo) fields.next();
+ descriptor.setField(field.getName(), field.getValue());
+ }
+ info.setMBeanDescriptor(descriptor);
+ } catch (MBeanException e) {
+ ;
+ }
+
+ return (info);
+
+ }
+
+
+ /**
+ * Return a string representation of this managed bean.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("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());
+
+ }
+
+
+}
diff --git a/java/org/apache/tomcat/util/modeler/NotificationInfo.java b/java/org/apache/tomcat/util/modeler/NotificationInfo.java
new file mode 100644
index 000000000..98e65566d
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/NotificationInfo.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.Descriptor;
+import javax.management.modelmbean.ModelMBeanNotificationInfo;
+
+
+/**
+ * Internal configuration information for a Notification
+ * descriptor.
ModelMBeanNotificationInfo object that corresponds
+ * to this NotificationInfo instance.
+ */
+ transient ModelMBeanNotificationInfo info = null;
+ protected String notifTypes[] = new String[0];
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * Override the description property setter.
+ *
+ * @param description The new description
+ */
+ public void setDescription(String description) {
+ super.setDescription(description);
+ this.info = null;
+ }
+
+
+ /**
+ * Override the name property setter.
+ *
+ * @param name The new name
+ */
+ public void setName(String name) {
+ super.setName(name);
+ this.info = null;
+ }
+
+
+ /**
+ * The set of notification types for this MBean.
+ */
+ public String[] getNotifTypes() {
+ return (this.notifTypes);
+ }
+
+
+ // --------------------------------------------------------- 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) {
+
+ synchronized (notifTypes) {
+ String results[] = new String[notifTypes.length + 1];
+ System.arraycopy(notifTypes, 0, results, 0, notifTypes.length);
+ results[notifTypes.length] = notifType;
+ notifTypes = results;
+ this.info = null;
+ }
+
+ }
+
+
+ /**
+ * Create and return a ModelMBeanNotificationInfo object that
+ * corresponds to the attribute described by this instance.
+ */
+ public ModelMBeanNotificationInfo createNotificationInfo() {
+
+ // Return our cached information (if any)
+ if (info != null)
+ return (info);
+
+ // Create and return a new information object
+ info = new ModelMBeanNotificationInfo
+ (getNotifTypes(), getName(), getDescription());
+ Descriptor descriptor = info.getDescriptor();
+ addFields(descriptor);
+ info.setDescriptor(descriptor);
+ return (info);
+
+ }
+
+
+ /**
+ * Return a string representation of this notification descriptor.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("NotificationInfo[");
+ sb.append("name=");
+ sb.append(name);
+ sb.append(", description=");
+ sb.append(description);
+ sb.append(", notifTypes=");
+ sb.append(notifTypes.length);
+ sb.append("]");
+ return (sb.toString());
+
+ }
+
+
+}
diff --git a/java/org/apache/tomcat/util/modeler/OperationInfo.java b/java/org/apache/tomcat/util/modeler/OperationInfo.java
new file mode 100644
index 000000000..6be9ea403
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/OperationInfo.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.Descriptor;
+import javax.management.MBeanParameterInfo;
+import javax.management.modelmbean.ModelMBeanOperationInfo;
+
+
+/**
+ * Internal configuration information for an Operation
+ * descriptor.
ModelMBeanOperationInfo object that corresponds
+ * to this OperationInfo instance.
+ */
+ transient ModelMBeanOperationInfo info = null;
+ protected String impact = "UNKNOWN";
+ protected String role = "operation";
+ protected String returnType = "void"; // FIXME - Validate
+ protected ParameterInfo parameters[] = new ParameterInfo[0];
+
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * Override the description property setter.
+ *
+ * @param description The new description
+ */
+ public void setDescription(String description) {
+ super.setDescription(description);
+ this.info = null;
+ }
+
+
+ /**
+ * Override the name property setter.
+ *
+ * @param name The new name
+ */
+ public void setName(String name) {
+ super.setName(name);
+ this.info = null;
+ }
+
+
+ /**
+ * 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();
+ }
+
+
+ /**
+ * The role of this operation ("getter", "setter", "operation", or
+ * "constructor").
+ */
+ public String getRole() {
+ return (this.role);
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+
+ /**
+ * The fully qualified Java class name of the return type for this
+ * operation.
+ */
+ public String getReturnType() {
+ return (this.returnType);
+ }
+
+ public void setReturnType(String returnType) {
+ this.returnType = returnType;
+ }
+
+ /**
+ * The set of parameters for this operation.
+ */
+ public ParameterInfo[] getSignature() {
+ return (this.parameters);
+ }
+
+ // --------------------------------------------------------- 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) {
+
+ synchronized (parameters) {
+ ParameterInfo results[] = new ParameterInfo[parameters.length + 1];
+ System.arraycopy(parameters, 0, results, 0, parameters.length);
+ results[parameters.length] = parameter;
+ parameters = results;
+ this.info = null;
+ }
+
+ }
+
+
+ /**
+ * Create and return a ModelMBeanOperationInfo object that
+ * corresponds to the attribute described by this instance.
+ */
+ public ModelMBeanOperationInfo createOperationInfo() {
+
+ // Return our cached information (if any)
+ if (info != null)
+ return (info);
+
+ // Create and return a new information object
+ ParameterInfo params[] = getSignature();
+ MBeanParameterInfo parameters[] =
+ new MBeanParameterInfo[params.length];
+ for (int i = 0; i < params.length; i++)
+ parameters[i] = params[i].createParameterInfo();
+ int impact = ModelMBeanOperationInfo.UNKNOWN;
+ if ("ACTION".equals(getImpact()))
+ impact = ModelMBeanOperationInfo.ACTION;
+ else if ("ACTION_INFO".equals(getImpact()))
+ impact = ModelMBeanOperationInfo.ACTION_INFO;
+ else if ("INFO".equals(getImpact()))
+ impact = ModelMBeanOperationInfo.INFO;
+
+ info = new ModelMBeanOperationInfo
+ (getName(), getDescription(), parameters,
+ getReturnType(), impact);
+ Descriptor descriptor = info.getDescriptor();
+ descriptor.removeField("class");
+ descriptor.setField("role", getRole());
+ addFields(descriptor);
+ info.setDescriptor(descriptor);
+ return (info);
+
+ }
+
+
+ /**
+ * Return a string representation of this operation descriptor.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("OperationInfo[");
+ sb.append("name=");
+ sb.append(name);
+ sb.append(", description=");
+ sb.append(description);
+ sb.append(", returnType=");
+ sb.append(returnType);
+ sb.append(", parameters=");
+ sb.append(parameters.length);
+ sb.append("]");
+ return (sb.toString());
+
+ }
+
+
+}
diff --git a/java/org/apache/tomcat/util/modeler/ParameterInfo.java b/java/org/apache/tomcat/util/modeler/ParameterInfo.java
new file mode 100644
index 000000000..13717bdf0
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/ParameterInfo.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.MBeanParameterInfo;
+
+
+/**
+ * Internal configuration information for a Parameter
+ * descriptor.
MBeanParameterInfo object that corresponds
+ * to this ParameterInfo instance.
+ */
+ transient MBeanParameterInfo info = null;
+ protected String type = null;
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * Override the description property setter.
+ *
+ * @param description The new description
+ */
+ public void setDescription(String description) {
+ super.setDescription(description);
+ this.info = null;
+ }
+
+
+ /**
+ * Override the name property setter.
+ *
+ * @param name The new name
+ */
+ public void setName(String name) {
+ super.setName(name);
+ this.info = null;
+ }
+
+
+ /**
+ * The fully qualified Java class name of this parameter.
+ */
+ public String getType() {
+ return (this.type);
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ this.info = null;
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Create and return a MBeanParameterInfo object that
+ * corresponds to the parameter described by this instance.
+ */
+ public MBeanParameterInfo createParameterInfo() {
+
+ // Return our cached information (if any)
+ if (info != null)
+ return (info);
+
+ // Create and return a new information object
+ info = new MBeanParameterInfo
+ (getName(), getType(), getDescription());
+ return (info);
+
+ }
+
+
+ /**
+ * Return a string representation of this parameter descriptor.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("ParameterInfo[");
+ sb.append("name=");
+ sb.append(name);
+ sb.append(", description=");
+ sb.append(description);
+ sb.append(", type=");
+ sb.append(type);
+ sb.append("]");
+ return (sb.toString());
+
+ }
+}
diff --git a/java/org/apache/tomcat/util/modeler/Registry.java b/java/org/apache/tomcat/util/modeler/Registry.java
new file mode 100644
index 000000000..1aac7dcaf
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/Registry.java
@@ -0,0 +1,1083 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed 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.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.management.DynamicMBean;
+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 javax.management.modelmbean.ModelMBean;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.modeler.modules.ModelerSource;
+
+/*
+ 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 beeing 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.
+ *
+ * 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.
+ *
+ * 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 {
+ /** Experimental support for manifest-based discovery.
+ */
+ public static String MODELER_MANIFEST="/META-INF/mbeans-descriptors.xml";
+
+ /**
+ * The Log instance to which we will write our log messages.
+ */
+ private static Log log = LogFactory.getLog(Registry.class);
+
+ // Support for the factory methods
+
+ /** Will be used to isolate different apps and enhance security
+ */
+ private static HashMap perLoaderRegistries=null;
+
+ /**
+ * The registry instance created by our factory method the first time
+ * it is called.
+ */
+ private static Registry registry = null;
+
+ // Per registy fields
+
+ /**
+ * The MBeanServer instance that we will use to register
+ * management beans.
+ */
+ private MBeanServer server = null;
+
+ /**
+ * The set of ManagedBean instances for the beans this registry
+ * knows about, keyed by name.
+ */
+ private HashMap descriptors = new HashMap();
+
+ /** List of managed byeans, keyed by class name
+ */
+ private HashMap descriptorsByClass = new HashMap();
+
+ // map to avoid duplicated searching or loading descriptors
+ private HashMap searchedPaths=new HashMap();
+
+ private Object key;
+ private Object guard;
+
+ // Id - small ints to use array access. No reset on stop()
+ private Hashtable idDomains=new Hashtable();
+ private Hashtable ids=new Hashtable();
+
+
+ // ----------------------------------------------------------- Constructors
+
+ /**
+ */
+ public Registry() {
+ super();
+ }
+
+ // -------------------- Static methods --------------------
+ // Factories
+
+ /**
+ * Factory method to create (if necessary) and return our
+ * Registry instance.
+ *
+ * Use this method to obtain a Registry - all other static methods
+ * are deprecated and shouldn't be used.
+ *
+ * The current version uses a static - future versions could use
+ * the thread class loader.
+ *
+ * @param key Support for application isolation. If null, the context class
+ * loader will be used ( if setUseContextClassLoader is called ) or the
+ * default registry is returned.
+ * @param guard Prevent access to the registry by untrusted components
+ *
+ * @since 1.1
+ */
+ public synchronized static Registry getRegistry(Object key, Object guard) {
+ Registry localRegistry;
+ if( perLoaderRegistries!=null ) {
+ if( key==null )
+ key=Thread.currentThread().getContextClassLoader();
+ if( key != null ) {
+ localRegistry=(Registry)perLoaderRegistries.get(key);
+ if( localRegistry == null ) {
+ localRegistry=new Registry();
+ localRegistry.key=key;
+ localRegistry.guard=guard;
+ perLoaderRegistries.put( key, localRegistry );
+ return localRegistry;
+ }
+ if( localRegistry.guard != null &&
+ localRegistry.guard != guard ) {
+ return null; // XXX Should I throw a permission ex ?
+ }
+ return localRegistry;
+ }
+ }
+
+ // static
+ if (registry == null) {
+ registry = new Registry();
+ }
+ if( registry.guard != null &&
+ registry.guard != guard ) {
+ return null;
+ }
+ return (registry);
+ }
+
+ /** Allow containers to isolate apps. Can be called only once.
+ * It is highly recommended you call this method if using Registry in
+ * a container environment. The default is false for backward compatibility
+ *
+ * @param enable
+ * @since 1.1
+ */
+ public static void setUseContextClassLoader( boolean enable ) {
+ if( enable ) {
+ perLoaderRegistries=new HashMap();
+ }
+ }
+
+ // -------------------- Generic methods --------------------
+
+ /** Set a guard object that will prevent access to this registry
+ * by unauthorized components
+ *
+ * @param guard
+ *
+ * @since 1.1
+ */
+ public void setGuard( Object guard ) {
+ if( this.guard!=null ) {
+ return; // already set, only once
+ }
+ this.guard=guard;
+ }
+
+ /** Lifecycle method - clean up the registry metadata.
+ *
+ * @since 1.1
+ */
+ public void stop() {
+ descriptorsByClass = new HashMap();
+ descriptors = new HashMap();
+ searchedPaths=new HashMap();
+ }
+
+ /**
+ * Load an extended mlet file. The source can be an URL, File or
+ * InputStream.
+ *
+ * All mbeans will be instantiated, registered and the attributes will be
+ * set. The result is a list of ObjectNames.
+ *
+ * @param source InputStream or URL of the file
+ * @param cl ClassLoader to be used to load the mbeans, or null to use the
+ * default JMX mechanism ( i.e. all registered loaders )
+ * @return List of ObjectName for the loaded mbeans
+ * @throws Exception
+ *
+ * @since 1.1
+ */
+ public List loadMBeans( Object source, ClassLoader cl )
+ throws Exception
+ {
+ return load("MbeansSource", source, null );
+ }
+
+
+ /** Load descriptors. The source can be a File or URL or InputStream for the
+ * descriptors file. In the case of File and URL, if the extension is ".ser"
+ * a serialized version will be loaded.
+ *
+ * Also ( experimental for now ) a ClassLoader - in which case META-INF/ will
+ * be used.
+ *
+ * This method should be used to explicitely load metadata - but this is not
+ * required in most cases. The registerComponent() method will find metadata
+ * in the same pacakge.
+ *
+ * @param source
+ */
+ public void loadMetadata(Object source ) throws Exception {
+ if( source instanceof ClassLoader ) {
+ loadMetaInfDescriptors((ClassLoader)source);
+ return;
+ } else {
+ loadDescriptors( null, source, null );
+ }
+
+ }
+
+ /** 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.
+ *
+ * @since 1.1
+ */
+ 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
+ *
+ * @since 1.1
+ */
+ 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
+ * @since 1.1
+ */
+ public void invoke( List mbeans, String operation, boolean failFirst )
+ throws Exception
+ {
+ if( mbeans==null ) {
+ return;
+ }
+ Iterator itr=mbeans.iterator();
+ while(itr.hasNext()) {
+ Object current=itr.next();
+ ObjectName oN=null;
+ try {
+ if( current instanceof ObjectName) {
+ oN=(ObjectName)current;
+ }
+ if( current instanceof String ) {
+ oN=new ObjectName( (String)current );
+ }
+ if( oN==null ) {
+ continue;
+ }
+ if( getMethodInfo(oN, operation) == null) {
+ continue;
+ }
+ getMBeanServer().invoke(oN, 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 An unique id for the domain:name combination
+ * @since 1.1
+ */
+ public synchronized int getId( String domain, String name) {
+ if( domain==null) {
+ domain="";
+ }
+ Hashtable domainTable=(Hashtable)idDomains.get( domain );
+ if( domainTable == null ) {
+ domainTable=new Hashtable();
+ idDomains.put( domain, domainTable);
+ }
+ if( name==null ) {
+ name="";
+ }
+ Integer i=(Integer)domainTable.get(name);
+
+ if( i!= null ) {
+ return i.intValue();
+ }
+
+ int id[]=(int [])ids.get( domain );
+ if( id == null ) {
+ id=new int[1];
+ ids.put( domain, id);
+ }
+ int code=id[0]++;
+ domainTable.put( name, new Integer( 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 null.
+ *
+ * @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.
+ * @since 1.0
+ */
+ public ManagedBean findManagedBean(String name) {
+ // XXX Group ?? Use Group + Type
+ ManagedBean mb=((ManagedBean) descriptors.get(name));
+ if( mb==null )
+ mb=(ManagedBean)descriptorsByClass.get(name);
+ return mb;
+ }
+
+ /**
+ * Return the set of bean names for all managed beans known to
+ * this registry.
+ *
+ * @since 1.0
+ */
+ public String[] findManagedBeans() {
+ return ((String[]) descriptors.keySet().toArray(new String[0]));
+ }
+
+
+ /**
+ * Return the set of bean names for all managed beans known to
+ * this registry that belong to the specified group.
+ *
+ * @param group Name of the group of interest, or null
+ * to select beans that do not belong to a group
+ * @since 1.0
+ */
+ public String[] findManagedBeans(String group) {
+
+ ArrayList results = new ArrayList();
+ Iterator items = descriptors.values().iterator();
+ while (items.hasNext()) {
+ ManagedBean item = (ManagedBean) items.next();
+ if ((group == null) && (item.getGroup() == null)) {
+ results.add(item.getName());
+ } else if (group.equals(item.getGroup())) {
+ results.add(item.getName());
+ }
+ }
+ String values[] = new String[results.size()];
+ return ((String[]) results.toArray(values));
+
+ }
+
+
+ /**
+ * Remove an existing bean from the set of beans known to this registry.
+ *
+ * @param bean The managed bean to be removed
+ * @since 1.0
+ */
+ public void removeManagedBean(ManagedBean bean) {
+ // TODO: change this to use group/name
+ descriptors.remove(bean.getName());
+ descriptorsByClass.remove( bean.getType());
+ }
+
+ // -------------------- Deprecated 1.0 methods --------------------
+
+ /**
+ * Factory method to create (if necessary) and return our
+ * MBeanServer instance.
+ *
+ * @since 1.0
+ * @deprecated Use the instance method
+ */
+ public static MBeanServer getServer() {
+ return Registry.getRegistry().getMBeanServer();
+ }
+
+ /**
+ * Set the MBeanServer to be utilized for our
+ * registered management beans.
+ *
+ * @param mbeanServer The new MBeanServer instance
+ * @since 1.0
+ * @deprecated Use the instance method
+ */
+ public static void setServer(MBeanServer mbeanServer) {
+ Registry.getRegistry().setMBeanServer(mbeanServer);
+ }
+
+ /**
+ * Load the registry from the XML input found in the specified input
+ * stream.
+ *
+ * @param stream InputStream containing the registry configuration
+ * information
+ *
+ * @exception Exception if any parsing or processing error occurs
+ * @deprecated use normal class method instead
+ * @since 1.0
+ */
+ public static void loadRegistry(InputStream stream) throws Exception {
+ Registry registry = getRegistry();
+ registry.loadMetadata(stream);
+ }
+
+ /** Get a "singelton" registry, or one per thread if setUseContextLoader
+ * was called
+ *
+ * @deprecated Not enough info - use the method that takes CL and domain
+ * @since 1.0
+ */
+ public synchronized static Registry getRegistry() {
+ return getRegistry(null, null);
+ }
+
+ // -------------------- Helpers --------------------
+
+ /** Get the type of an attribute of the object, from the metadata.
+ *
+ * @param oname
+ * @param attName
+ * @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=server.getMBeanInfo(oname);
+ } catch (Exception e) {
+ log.info( "Can't find metadata for object" + oname );
+ return null;
+ }
+
+ MBeanAttributeInfo attInfo[]=info.getAttributes();
+ for( int i=0; iMBeanServer to be utilized for our
+ * registered management beans.
+ *
+ * @param server The new MBeanServer instance
+ */
+ public void setMBeanServer( MBeanServer server ) {
+ this.server=server;
+ }
+
+ public void resetMetadata() {
+ stop();
+ }
+ /**
+ * Load the registry from the XML input found in the specified input
+ * stream.
+ *
+ * @param source Source to be used to load. Can be an InputStream or URL.
+ *
+ * @exception Exception if any parsing or processing error occurs
+ */
+ public void loadDescriptors( Object source )
+ throws Exception
+ {
+ loadDescriptors("MbeansDescriptorsDOMSource", source, null );
+ }
+
+ /** @deprecated - may still be used in code using pre-1.1 builds
+ */
+ public void registerComponent(Object bean, String domain, String type,
+ String name)
+ throws Exception
+ {
+ StringBuffer sb=new StringBuffer();
+ sb.append( domain ).append(":");
+ sb.append( name );
+ String nameStr=sb.toString();
+ ObjectName oname=new ObjectName( nameStr );
+ registerComponent(bean, oname, type );
+ }
+
+
+
+ // should be removed
+ public void unregisterComponent( String domain, String name ) {
+ try {
+ ObjectName oname=new ObjectName( domain + ":" + name );
+
+ // XXX remove from our tables.
+ getMBeanServer().unregisterMBean( oname );
+ } catch( Throwable t ) {
+ log.error( "Error unregistering mbean ", t );
+ }
+ }
+
+ public List loadMBeans( Object source )
+ throws Exception
+ {
+ return loadMBeans( source, null );
+ }
+
+
+ /**
+ * Load the registry from a cached .ser file. This is typically 2-3 times
+ * faster than parsing the XML.
+ *
+ * @param source Source to be used to load. Can be an InputStream or URL.
+ *
+ * @exception Exception if any parsing or processing error occurs
+ * @deprecated Loaded automatically or using a File or Url ending in .ser
+ */
+ public void loadCachedDescriptors( Object source )
+ throws Exception
+ {
+ loadDescriptors("MbeansDescriptorsSerSource", source, null );
+ }
+}
diff --git a/java/org/apache/tomcat/util/modeler/RegistryMBean.java b/java/org/apache/tomcat/util/modeler/RegistryMBean.java
new file mode 100644
index 000000000..b77430135
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/RegistryMBean.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+/**
+ * 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 {
+
+ /**
+ * Load an extended mlet file. The source can be an URL, File or
+ * InputStream.
+ *
+ * All mbeans will be instantiated, registered and the attributes will be
+ * set. The result is a list of ObjectNames.
+ *
+ * @param source InputStream or URL of the file
+ * @param cl ClassLoader to be used to load the mbeans, or null to use the
+ * default JMX mechanism ( i.e. all registered loaders )
+ * @return List of ObjectName for the loaded mbeans
+ * @throws Exception
+ *
+ * @since 1.1
+ */
+ public List loadMBeans( Object source, ClassLoader cl ) throws Exception;
+
+ /** 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
+ */
+ public void invoke( List 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.
+ *
+ * @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
+ *
+ * @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 An 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();
+
+ /** Load descriptors. The source can be a File, URL pointing to an
+ * mbeans-descriptors.xml.
+ *
+ * Also ( experimental for now ) a ClassLoader - in which case META-INF/ will
+ * be used.
+ *
+ * @param source
+ */
+ public void loadMetadata(Object source ) throws Exception;
+}
diff --git a/java/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd b/java/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd
new file mode 100644
index 000000000..231203e8f
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDOMSource.java b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDOMSource.java
new file mode 100644
index 000000000..3b7314ccb
--- /dev/null
+++ b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDOMSource.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed 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.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.DomUtil;
+import org.apache.tomcat.util.modeler.AttributeInfo;
+import org.apache.tomcat.util.modeler.ConstructorInfo;
+import org.apache.tomcat.util.modeler.FieldInfo;
+import org.apache.tomcat.util.modeler.ManagedBean;
+import org.apache.tomcat.util.modeler.NotificationInfo;
+import org.apache.tomcat.util.modeler.OperationInfo;
+import org.apache.tomcat.util.modeler.ParameterInfo;
+import org.apache.tomcat.util.modeler.Registry;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+
+public class MbeansDescriptorsDOMSource extends ModelerSource
+{
+ private static Log log = LogFactory.getLog(MbeansDescriptorsDOMSource.class);
+
+ Registry registry;
+ String location;
+ String type;
+ Object source;
+ List mbeans=new ArrayList();
+
+ public void setRegistry(Registry reg) {
+ this.registry=reg;
+ }
+
+ public void setLocation( String loc ) {
+ this.location=loc;
+ }
+
+ /** Used if a single component is loaded
+ *
+ * @param type
+ */
+ public void setType( String type ) {
+ this.type=type;
+ }
+
+ public void setSource( Object source ) {
+ this.source=source;
+ }
+
+ public List loadDescriptors( Registry registry, String location,
+ String type, Object source)
+ throws Exception
+ {
+ setRegistry(registry);
+ setLocation(location);
+ setType(type);
+ setSource(source);
+ execute();
+ return mbeans;
+ }
+
+ public void execute() throws Exception {
+ if( registry==null ) registry=Registry.getRegistry();
+
+ try {
+ InputStream stream=(InputStream)source;
+ long t1=System.currentTimeMillis();
+ Document doc=DomUtil.readXml(stream);
+ // Ignore for now the name of the root element
+ Node descriptorsN=doc.getDocumentElement();
+ //Node descriptorsN=DomUtil.getChild(doc, "mbeans-descriptors");
+ if( descriptorsN == null ) {
+ log.error("No descriptors found");
+ return;
+ }
+
+ Node firstMbeanN=null;
+ if( "mbean".equals( descriptorsN.getNodeName() ) ) {
+ firstMbeanN=descriptorsN;
+ } else {
+ firstMbeanN=DomUtil.getChild(descriptorsN, "mbean");
+ }
+
+ if( firstMbeanN==null ) {
+ log.error(" No mbean tags ");
+ return;
+ }
+
+ // Process each 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 ) indepedently.
+ +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. +
+ +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.
+ +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.
+ +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. +
+ +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. +
+ + + diff --git a/java/org/apache/tomcat/util/modeler/package.html b/java/org/apache/tomcat/util/modeler/package.html new file mode 100644 index 000000000..4d5aa6818 --- /dev/null +++ b/java/org/apache/tomcat/util/modeler/package.html @@ -0,0 +1,232 @@ + + +The Modeler component of the Jakarta Commons subproject +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 + +JMX Specification (Version 1.1) for more information about Model MBeans +and other JMX concepts.
+ +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
+javax.management.modelmbean.ModelMBeanInfo interface and its
+corresponding subordinate interfaces). Creating this information can be
+tedious and error prone. The Modeler 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
+Registry, Modeler also supports
+convenient factory methods to instantiate new Model MBean instances for you.
+
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 src/test subdirectory of the
+source distribution), and much more complex usage code in Tomcat 4.1 (in the
+org.apache.catalina.mbeans package).
Modeler has been tested with different JMX implementations: +
After unpacking the release, you will need to ensure that the appropriate
+JAR file (jmxri.jar or mx4j.jar) is included on your
+compilation classpath, and in the classpath of your server application when it
+is executed.
Modeler requires that you construct a configuration file that
+describes the metadata ultimately need to construct the
+javax.management.modelmbean.ModelMBeanInfo structure that is
+required by JMX. Your XML file must conform to the
+mbeans-descriptors.dtd
+DTD that defines the acceptable structure.
Fundamentally, you will be constructing an <mbean>
+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.
A simple example configuration file might include the following components +(abstracted from the real definitions found in Tomcat 4.1's use of Modeler): +
++ + <?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> + ++ +
This MBean represents an instance of org.apache.catalina.Group,
+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 (writeable="false"). Finally,
+this MBean supports three operations (addRole, removeRole, and
+removeRoles) that roughly correspond to JavaBean methods on the underlying
+component.
In general, Modeler 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 +BaseModelMBean 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). + +
For this particular MBean, a custom BaseModelMBean implementation subclass
+is described (org.apache.catalina.mbeans.GroupMBean) 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 Group interface:
+
+ public void addRole(Role role); ++
is represented, in the MBean, by an addRole 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 addRole method on the
+underlying Group instance within the Server.
The metadata information, and the corresponding Model MBean factory, is +represented at runtime in an instance of Registry +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: +
+
+ URL url= this.getClass().getResource
+ ("/com/mycompany/mypackage/mbeans-descriptors.xml");
+ Registry registry = Registry.getRegistry();
+ registry.loadMetadata(url);
+
+
+Besides using the configuration file, it is possible to configure the
+registry metadata by hand, using the addManagedBean() and
+removeManagedBean() methods. However, most users will find
+the standard support for loading a configuration file to be convenient
+and sufficient.
Modeler will also look for a mbeans-descriptors.xml in the same package +with the class beeing 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
+ +In a future version we should also support xdoclet-based generation of the +descriptors
+ + +When your server application needs to instantiate a new MBean and register
+it with the corresponding MBeanServer, it can execute code like
+this:
+ Group group = ... managed component instance ...; + + MBeanServer mserver = registry.getMBeanServer(); + + String oname="myDomain:type=Group,name=myGroup"; + + registry.registerComponent( group, oname, "Group" ); ++ +
After the Model MBean has been created and registered, it is accessible to +JMX clients through the standard JMX client APIs. +
+ + + diff --git a/res/bootstrap.jar.manifest b/res/bootstrap.jar.manifest index 045e7a762..4ccb7029b 100644 --- a/res/bootstrap.jar.manifest +++ b/res/bootstrap.jar.manifest @@ -1,5 +1,5 @@ Manifest-Version: 1.0 Main-Class: org.apache.catalina.startup.Bootstrap -Class-Path: commons-daemon.jar commons-logging-api.jar tomcat-juli.jar tomcat-util.jar +Class-Path: commons-daemon.jar commons-logging-api.jar tomcat-juli.jar tomcat-coyote.jar Specification-Title: Catalina Specification-Version: 6.0 \ No newline at end of file