From: remm Date: Thu, 30 Mar 2006 00:55:22 +0000 (+0000) Subject: - Reduce the number of JARs. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=4114fb98b3f88e549747e5d51ef33cb5457dd9ef;p=tomcat7.0 - Reduce the number of JARs. - Is it me, or are the JARs magically smaller ? There must be something related to JDK 1.5. - bootstrap.jar is really needed. - Import modeler. I think there are some serious possibilities to enhance XML processing, as everything (or almost everything, as I don't think the modeler does at the moment) goes through digester. - I suppose the webapps could be added now. git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@389946 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/build.properties.default b/build.properties.default index f04925187..d66c22a01 100644 --- a/build.properties.default +++ b/build.properties.default @@ -18,11 +18,7 @@ base.path=/usr/share/java #base.path=/usr/local compile.source=1.5 - -# ----- Servlet API v2.4 ----- -servlet-api.home=${base.path}/servlet-api-2.4 -servlet-api.lib=${servlet-api.home}/lib -servlet-api.jar=${servlet-api.lib}/servlet-api.jar +compile.target=1.5 # ----- Commons Logging, version 1.0.1 or later ----- commons-logging.home=${base.path}/commons-logging-1.0.4 @@ -31,12 +27,6 @@ commons-logging-api.jar=${commons-logging.lib}/commons-logging-api.jar commons-logging.jar=${commons-logging.lib}/commons-logging.jar commons-logging.loc=${base-jakarta.loc}/commons/logging/binaries/commons-logging-1.0.4.tar.gz -# ----- Commons Modeler, version 1.1 or later ----- -commons-modeler.home=${base.path}/commons-modeler-1.1 -commons-modeler.lib=${commons-modeler.home} -commons-modeler.jar=${commons-modeler.lib}/commons-modeler.jar -commons-modeler.loc=${base-jakarta.loc}/commons/modeler/binaries/modeler-1.1.tar.gz - # ----- Eclipse JDT, version 3.1.2 or later ----- jdt.home=${base.path}/eclipse/plugins jdt.lib=${jdt.home} diff --git a/build.xml b/build.xml index 093c4826d..d530c105f 100644 --- a/build.xml +++ b/build.xml @@ -35,27 +35,17 @@ + + - - - - - - - - - - - - - + @@ -63,7 +53,6 @@ - @@ -77,6 +66,7 @@ + @@ -95,10 +85,12 @@ - + + + @@ -109,7 +101,7 @@ - + @@ -121,7 +113,7 @@ - + @@ -131,7 +123,7 @@ - + @@ -140,10 +132,32 @@ + + + + + + + + + + + + + + + + + + + + - + + @@ -151,14 +165,12 @@ - - - + @@ -169,7 +181,7 @@ - + @@ -178,179 +190,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -363,7 +227,7 @@ - + @@ -373,6 +237,13 @@ + + + + + + + diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java b/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java index 8aa749b4f..31bbbfa40 100644 --- a/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java +++ b/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java @@ -174,7 +174,7 @@ public class JMXAccessorQueryTask extends JMXAccessorTask { try { MBeanInfo minfo = jmxServerConnection.getMBeanInfo(oname); String code = minfo.getClassName(); - if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) { + if ("org.apache.tomcat.util.modeler.BaseModelMBean".equals(code)) { code = (String) jmxServerConnection.getAttribute(oname, "modelerType"); } diff --git a/java/org/apache/catalina/connector/Connector.java b/java/org/apache/catalina/connector/Connector.java index 234771cf6..2e32c8263 100644 --- a/java/org/apache/catalina/connector/Connector.java +++ b/java/org/apache/catalina/connector/Connector.java @@ -36,11 +36,11 @@ import org.apache.catalina.util.LifecycleSupport; 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.coyote.Adapter; import org.apache.coyote.ProtocolHandler; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.http.mapper.Mapper; +import org.apache.tomcat.util.modeler.Registry; /** diff --git a/java/org/apache/catalina/connector/MapperListener.java b/java/org/apache/catalina/connector/MapperListener.java index 80ebe95dd..8e06b644c 100644 --- a/java/org/apache/catalina/connector/MapperListener.java +++ b/java/org/apache/catalina/connector/MapperListener.java @@ -28,9 +28,9 @@ import javax.management.ObjectName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.commons.modeler.Registry; import org.apache.tomcat.util.http.mapper.Mapper; +import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.res.StringManager; diff --git a/java/org/apache/catalina/core/ContainerBase.java b/java/org/apache/catalina/core/ContainerBase.java index bf604d279..bf34aec54 100644 --- a/java/org/apache/catalina/core/ContainerBase.java +++ b/java/org/apache/catalina/core/ContainerBase.java @@ -54,8 +54,8 @@ import org.apache.catalina.util.LifecycleSupport; 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.naming.resources.ProxyDirContext; +import org.apache.tomcat.util.modeler.Registry; /** diff --git a/java/org/apache/catalina/core/NamingContextListener.java b/java/org/apache/catalina/core/NamingContextListener.java index 996265886..c5a9d35c7 100644 --- a/java/org/apache/catalina/core/NamingContextListener.java +++ b/java/org/apache/catalina/core/NamingContextListener.java @@ -54,7 +54,6 @@ import org.apache.catalina.deploy.NamingResources; 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.naming.ContextAccessController; import org.apache.naming.ContextBindings; import org.apache.naming.EjbRef; @@ -63,6 +62,7 @@ import org.apache.naming.ResourceEnvRef; import org.apache.naming.ResourceLinkRef; import org.apache.naming.ResourceRef; import org.apache.naming.TransactionRef; +import org.apache.tomcat.util.modeler.Registry; /** diff --git a/java/org/apache/catalina/core/StandardContext.java b/java/org/apache/catalina/core/StandardContext.java index e2d8c1be5..b4875b13c 100644 --- a/java/org/apache/catalina/core/StandardContext.java +++ b/java/org/apache/catalina/core/StandardContext.java @@ -90,7 +90,6 @@ import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.URLEncoder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.commons.modeler.Registry; import org.apache.naming.ContextBindings; import org.apache.naming.resources.BaseDirContext; import org.apache.naming.resources.DirContextURLStreamHandler; @@ -98,6 +97,7 @@ import org.apache.naming.resources.FileDirContext; import org.apache.naming.resources.ProxyDirContext; import org.apache.naming.resources.WARDirContext; import org.apache.tomcat.util.compat.JdkCompat; +import org.apache.tomcat.util.modeler.Registry; /** * Standard implementation of the Context interface. Each diff --git a/java/org/apache/catalina/core/StandardEngine.java b/java/org/apache/catalina/core/StandardEngine.java index 976597eb0..98cace689 100644 --- a/java/org/apache/catalina/core/StandardEngine.java +++ b/java/org/apache/catalina/core/StandardEngine.java @@ -35,8 +35,8 @@ import org.apache.catalina.realm.JAASRealm; import org.apache.catalina.util.ServerInfo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.commons.modeler.Registry; -import org.apache.commons.modeler.modules.MbeansSource; +import org.apache.tomcat.util.modeler.Registry; +import org.apache.tomcat.util.modeler.modules.MbeansSource; /** * Standard implementation of the Engine interface. Each diff --git a/java/org/apache/catalina/core/StandardHost.java b/java/org/apache/catalina/core/StandardHost.java index 2b1505faf..5b9d8e359 100644 --- a/java/org/apache/catalina/core/StandardHost.java +++ b/java/org/apache/catalina/core/StandardHost.java @@ -28,7 +28,7 @@ import org.apache.catalina.LifecycleException; import org.apache.catalina.Valve; import org.apache.catalina.startup.HostConfig; import org.apache.catalina.valves.ValveBase; -import org.apache.commons.modeler.Registry; +import org.apache.tomcat.util.modeler.Registry; /** diff --git a/java/org/apache/catalina/core/StandardPipeline.java b/java/org/apache/catalina/core/StandardPipeline.java index 819b21fba..d0499f02c 100644 --- a/java/org/apache/catalina/core/StandardPipeline.java +++ b/java/org/apache/catalina/core/StandardPipeline.java @@ -34,7 +34,7 @@ import org.apache.catalina.util.StringManager; import org.apache.catalina.valves.ValveBase; 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/core/StandardServer.java b/java/org/apache/catalina/core/StandardServer.java index fb6594de3..908b3791f 100644 --- a/java/org/apache/catalina/core/StandardServer.java +++ b/java/org/apache/catalina/core/StandardServer.java @@ -45,8 +45,8 @@ import org.apache.catalina.util.StringManager; import org.apache.catalina.util.ServerInfo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.commons.modeler.Registry; import org.apache.tomcat.util.buf.StringCache; +import org.apache.tomcat.util.modeler.Registry; diff --git a/java/org/apache/catalina/core/StandardService.java b/java/org/apache/catalina/core/StandardService.java index 4ffce27ff..707c823cc 100644 --- a/java/org/apache/catalina/core/StandardService.java +++ b/java/org/apache/catalina/core/StandardService.java @@ -36,7 +36,7 @@ import org.apache.catalina.util.LifecycleSupport; 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/core/StandardWrapper.java b/java/org/apache/catalina/core/StandardWrapper.java index 4bbea6af3..96b8734c5 100644 --- a/java/org/apache/catalina/core/StandardWrapper.java +++ b/java/org/apache/catalina/core/StandardWrapper.java @@ -57,7 +57,7 @@ import org.apache.catalina.util.Enumerator; import org.apache.catalina.util.InstanceSupport; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.log.SystemLogHandler; -import org.apache.commons.modeler.Registry; +import org.apache.tomcat.util.modeler.Registry; /** * Standard implementation of the Wrapper interface that represents diff --git a/java/org/apache/catalina/loader/WebappLoader.java b/java/org/apache/catalina/loader/WebappLoader.java index 81d4cee27..7d9bf3b4b 100644 --- a/java/org/apache/catalina/loader/WebappLoader.java +++ b/java/org/apache/catalina/loader/WebappLoader.java @@ -57,10 +57,10 @@ import org.apache.catalina.Loader; import org.apache.catalina.core.StandardContext; import org.apache.catalina.util.LifecycleSupport; import org.apache.catalina.util.StringManager; -import org.apache.commons.modeler.Registry; import org.apache.naming.resources.DirContextURLStreamHandler; import org.apache.naming.resources.DirContextURLStreamHandlerFactory; import org.apache.naming.resources.Resource; +import org.apache.tomcat.util.modeler.Registry; /** diff --git a/java/org/apache/catalina/mbeans/ClassNameMBean.java b/java/org/apache/catalina/mbeans/ClassNameMBean.java index dc93fe115..9e132d6d9 100644 --- a/java/org/apache/catalina/mbeans/ClassNameMBean.java +++ b/java/org/apache/catalina/mbeans/ClassNameMBean.java @@ -19,7 +19,8 @@ package org.apache.catalina.mbeans; import javax.management.MBeanException; 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/ContextEnvironmentMBean.java b/java/org/apache/catalina/mbeans/ContextEnvironmentMBean.java index f498102c4..6b59ddf5a 100644 --- a/java/org/apache/catalina/mbeans/ContextEnvironmentMBean.java +++ b/java/org/apache/catalina/mbeans/ContextEnvironmentMBean.java @@ -27,7 +27,7 @@ import javax.management.modelmbean.InvalidTargetObjectTypeException; import org.apache.catalina.deploy.ContextEnvironment; import org.apache.catalina.deploy.NamingResources; -import org.apache.commons.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.BaseModelMBean; /** diff --git a/java/org/apache/catalina/mbeans/ContextResourceLinkMBean.java b/java/org/apache/catalina/mbeans/ContextResourceLinkMBean.java index a1a3b594d..322fc80ed 100644 --- a/java/org/apache/catalina/mbeans/ContextResourceLinkMBean.java +++ b/java/org/apache/catalina/mbeans/ContextResourceLinkMBean.java @@ -27,7 +27,7 @@ import javax.management.modelmbean.InvalidTargetObjectTypeException; import org.apache.catalina.deploy.ContextResourceLink; import org.apache.catalina.deploy.NamingResources; -import org.apache.commons.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.BaseModelMBean; /** diff --git a/java/org/apache/catalina/mbeans/ContextResourceMBean.java b/java/org/apache/catalina/mbeans/ContextResourceMBean.java index e86bd6dc7..ed15b9c51 100644 --- a/java/org/apache/catalina/mbeans/ContextResourceMBean.java +++ b/java/org/apache/catalina/mbeans/ContextResourceMBean.java @@ -27,7 +27,7 @@ import javax.management.modelmbean.InvalidTargetObjectTypeException; import org.apache.catalina.deploy.ContextResource; import org.apache.catalina.deploy.NamingResources; -import org.apache.commons.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.BaseModelMBean; /** diff --git a/java/org/apache/catalina/mbeans/DefaultContextMBean.java b/java/org/apache/catalina/mbeans/DefaultContextMBean.java index 7460a2b34..767c52664 100644 --- a/java/org/apache/catalina/mbeans/DefaultContextMBean.java +++ b/java/org/apache/catalina/mbeans/DefaultContextMBean.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/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; iInternal configuration information for an Attribute + * descriptor.

+ * + * @author Craig R. McClanahan + * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ + */ + +public class AttributeInfo extends FeatureInfo implements Serializable { + static final long serialVersionUID = -2511626862303972143L; + + // ----------------------------------------------------- Instance Variables + + + /** + * The 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; + + +/** + *

Implementation of 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.

+ * + * @author Craig R. McClanahan + * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ + */ + +public class BaseAttributeFilter implements NotificationFilter { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new filter that accepts only the specified attribute + * name. + * + * @param name Name of the attribute to be accepted by this filter, or + * 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()])); + } + + } + + + /** + *

Test whether notification enabled for this event. + * Return true if:

+ *
    + *
  • This is an attribute change notification
  • + *
  • Either the set of accepted names is empty (implying that all + * attribute names are of interest) or the set of accepted names + * includes the name of the attribute in this notification
  • + *
+ */ + 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 ) + +/** + *

Basic implementation of the ModelMBean interface, which + * supports the minimal requirements of the interface contract.

+ * + *

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: + *

    + *
  • Only managed resources of type objectReference are + * supportd.
  • + *
  • Caching of attribute values and operation results is not supported. + * All calls to invoke() are immediately executed.
  • + *
  • Logging (under control of descriptors) is not supported.
  • + *
  • Persistence of MBean attributes and operations is not supported.
  • + *
  • All classes referenced as attribute types, operation parameters, or + * operation return values must be one of the following: + *
      + *
    • One of the Java primitive types (boolean, byte, char, double, + * float, integer, long, short). Corresponding value will be wrapped + * in the appropriate wrapper class automatically.
    • + *
    • Operations that return no value should declare a return type of + * void.
    • + *
    + *
  • Attribute caching is not supported
  • + *
+ * + * @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 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 , it should create + // the resource + setModeledType(type); + } catch( Throwable ex ) { + log.error( "Error creating mbean ", ex); + } + } + + public BaseModelMBean( String type, ModelerSource source ) + throws MBeanException, RuntimeOperationsException + { + try { + setModeledType(type); + } catch( Throwable ex ) { + log.error( "Error creating mbean ", ex); + } + this.source=source; + } + + // ----------------------------------------------------- Instance Variables + + + /** + * Notification broadcaster for attribute changes. + */ + protected BaseNotificationBroadcaster attributeBroadcaster = null; + + /** Registry we are associated with + */ + protected Registry registry=null; + + /** + * Notification broadcaster for general notifications. + */ + protected BaseNotificationBroadcaster generalBroadcaster = null; + + protected ObjectName oname=null; + + /** + * The 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. + * + *

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.

+ * + * @param name Name of the operation to be invoked + * @param params Array containing the method parameters of this operation + * @param signature Array containing the class names representing + * the signature of this operation + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception ReflectioNException if a Java reflection exception + * occurs when invoking a method + */ + public Object invoke(String name, Object params[], String signature[]) + throws MBeanException, ReflectionException + { + if( (resource instanceof DynamicMBean) && + ! ( resource instanceof BaseModelMBean )) { + return ((DynamicMBean)resource).invoke(name, params, signature); + } + + // Validate the input parameters + if (name == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Method name is null"), + "Method name is null"); + + if( log.isDebugEnabled()) log.debug("Invoke " + name); + MethodKey mkey = new MethodKey(name, signature); + Method method=(Method)invokeAttMap.get(mkey); + if( method==null ) { + if (params == null) + params = new Object[0]; + if (signature == null) + signature = new String[0]; + if (params.length != signature.length) + throw new RuntimeOperationsException + (new IllegalArgumentException("Inconsistent arguments and signature"), + "Inconsistent arguments and signature"); + + // Acquire the ModelMBeanOperationInfo information for + // the requested operation + ModelMBeanOperationInfo opInfo = info.getOperation(name); + if (opInfo == null) + throw new MBeanException + (new ServiceNotFoundException("Cannot find operation " + name), + "Cannot find operation " + name); + + // Prepare the signature required by Java reflection APIs + // FIXME - should we use the signature from opInfo? + Class types[] = new Class[signature.length]; + for (int i = 0; i < signature.length; i++) { + types[i]=getAttributeClass( signature[i] ); + } + + // Locate the method to be invoked, either in this MBean itself + // or in the corresponding managed resource + // FIXME - Accessible methods in superinterfaces? + Object object = null; + Exception exception = null; + try { + object = this; + method = object.getClass().getMethod(name, types); + } catch (NoSuchMethodException e) { + exception = e;; + } + try { + if ((method == null) && (resource != null)) { + object = resource; + method = object.getClass().getMethod(name, types); + } + } catch (NoSuchMethodException e) { + exception = e; + } + if (method == null) { + throw new ReflectionException(exception, + "Cannot find method " + name + + " with this signature"); + } + invokeAttMap.put( mkey, method ); + } + + // Invoke the selected method on the appropriate object + Object result = null; + try { + if( method.getDeclaringClass().isAssignableFrom( this.getClass()) ) { + result = method.invoke(this, params ); + } else { + result = method.invoke(resource, params); + } + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + log.error("Exception invoking method " + name , t ); + if (t == null) + t = e; + if (t instanceof RuntimeException) + throw new RuntimeOperationsException + ((RuntimeException) t, "Exception invoking method " + name); + else if (t instanceof Error) + throw new RuntimeErrorException + ((Error) t, "Error invoking method " + name); + else + throw new MBeanException + ((Exception)t, "Exception invoking method " + name); + } catch (Exception e) { + log.error("Exception invoking method " + name , e ); + throw new MBeanException + (e, "Exception invoking method " + name); + } + + // Return the results of this method invocation + // FIXME - should we validate the return type? + return (result); + + } + + private Class getAttributeClass(String signature) + throws ReflectionException + { + if (signature.equals(Boolean.TYPE.getName())) + return Boolean.TYPE; + else if (signature.equals(Byte.TYPE.getName())) + return Byte.TYPE; + else if (signature.equals(Character.TYPE.getName())) + return Character.TYPE; + else if (signature.equals(Double.TYPE.getName())) + return Double.TYPE; + else if (signature.equals(Float.TYPE.getName())) + return Float.TYPE; + else if (signature.equals(Integer.TYPE.getName())) + return Integer.TYPE; + else if (signature.equals(Long.TYPE.getName())) + return Long.TYPE; + else if (signature.equals(Short.TYPE.getName())) + return Short.TYPE; + else { + try { + ClassLoader cl=Thread.currentThread().getContextClassLoader(); + if( cl!=null ) + return cl.loadClass(signature); + } catch( ClassNotFoundException e ) { + } + try { + return Class.forName(signature); + } catch (ClassNotFoundException e) { + throw new ReflectionException + (e, "Cannot find Class for " + signature); + } + } + } + + /** + * Set the value of a specific attribute of this MBean. + * + * @param attribute The identification of the attribute to be set + * and the new value + * + * @exception AttributeNotFoundException if this attribute is not + * supported by this MBean + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception ReflectionException if a Java reflection exception + * occurs when invoking the getter + */ + public void setAttribute(Attribute attribute) + throws AttributeNotFoundException, MBeanException, + ReflectionException + { + if( log.isDebugEnabled() ) + log.debug("Setting attribute " + this + " " + attribute ); + + if( (resource instanceof DynamicMBean) && + ! ( resource instanceof BaseModelMBean )) { + try { + ((DynamicMBean)resource).setAttribute(attribute); + } catch (InvalidAttributeValueException e) { + throw new MBeanException(e); + } + return; + } + + // Validate the input parameters + if (attribute == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Attribute is null"), + "Attribute is null"); + + String name = attribute.getName(); + Object value = attribute.getValue(); + + if (name == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Attribute name is null"), + "Attribute name is null"); + + 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"); + + Object oldValue=null; + if( getAttMap.get(name) != null ) + oldValue=getAttribute( name ); + + + // Extract the method from cache + Method m=(Method)setAttMap.get( name ); + + if( m==null ) { + // Look up the actual operation to be used + String setMethod = (String) attrDesc.getFieldValue("setMethod"); + if (setMethod == null) + throw new AttributeNotFoundException("Cannot find attribute " + name + " set method name"); + + String argType=attrInfo.getType(); + + Class signature[] = new Class[] { getAttributeClass( argType ) }; + + Object object = null; + NoSuchMethodException exception = null; + try { + object = this; + m = object.getClass().getMethod(setMethod, signature); + } catch (NoSuchMethodException e) { + exception = e;; + } + if( m== null && resource != null ) { + try { + object = resource; + m = object.getClass().getMethod(setMethod, signature); + exception=null; + } catch (NoSuchMethodException e) { + if( log.isDebugEnabled()) + log.debug("Method not found in resource " +resource); + exception = e; + } + } + if( exception != null ) + throw new ReflectionException(exception, + "Cannot find setter method " + setMethod + + " " + resource); + setAttMap.put( name, m ); + } + + Object result = null; + try { + if( m.getDeclaringClass().isAssignableFrom( this.getClass()) ) { + result = m.invoke(this, new Object[] { value }); + } else { + result = m.invoke(resource, new Object[] { value }); + } + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + if (t == null) + t = e; + if (t instanceof RuntimeException) + throw new RuntimeOperationsException + ((RuntimeException) t, "Exception invoking method " + name); + else if (t instanceof Error) + throw new RuntimeErrorException + ((Error) t, "Error invoking method " + name); + else + throw new MBeanException + (e, "Exception invoking method " + name); + } catch (Exception e) { + log.error("Exception invoking method " + name , e ); + throw new MBeanException + (e, "Exception invoking method " + name); + } + try { + sendAttributeChangeNotification(new Attribute( name, oldValue), + attribute); + } catch(Exception ex) { + log.error("Error sending notification " + name, ex); + } + attributes.put( name, value ); + if( source != null ) { + // this mbean is asscoiated with a source - maybe we want to persist + source.updateField(oname, name, value); + } + } + + public String toString() { + if( resource==null ) + return "BaseModelMbean[" + resourceType + "]"; + return resource.toString(); + } + + /** + * Set the values of several attributes of this MBean. + * + * @param attributes THe names and values to be set + * + * @return The list of attributes that were set and their new values + */ + public AttributeList setAttributes(AttributeList attributes) { + + // Validate the input parameters + if (attributes == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Attributes list is null"), + "Attributes list is null"); + + // Prepare and return our response, eating all exceptions + AttributeList response = new AttributeList(); + String names[] = new String[attributes.size()]; + int n = 0; + Iterator items = attributes.iterator(); + while (items.hasNext()) { + Attribute item = (Attribute) items.next(); + names[n++] = item.getName(); + try { + setAttribute(item); + } catch (Exception e) { + ; // Ignore all exceptions + } + } + + return (getAttributes(names)); + + } + + + // ----------------------------------------------------- ModelMBean Methods + + + /** + * Get the instance handle of the object against which we execute + * all methods in this ModelMBean management interface. + * + * @exception InstanceNotFoundException if the managed resource object + * cannot be found + * @exception MBeanException if the initializer of the object throws + * an exception + * @exception RuntimeOperationsException if the managed resource or the + * resource type is 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. + * + *

IMPLEMENTATION NOTE - This implementation does + * not support persistence.

+ * + * @exception InstanceNotFoundException if the managed resource object + * cannot be found + * @exception MBeanException if the initializer of the object throws + * an exception + * @exception RuntimeOperationsException if an exception is reported + * by the persistence mechanism + */ + public void load() throws InstanceNotFoundException, + MBeanException, RuntimeOperationsException { + // XXX If a context was set, use it to load the data + throw new MBeanException + (new IllegalStateException("Persistence is not supported"), + "Persistence is not supported"); + + } + + + /** + * Capture the current state of this MBean instance and write it out + * to the persistent store. The state stored could include attribute + * and operation values. If one of these methods of persistence is not + * supported, a "service not found" exception will be thrown. + * + *

IMPLEMENTATION NOTE - This implementation does + * not support persistence.

+ * + * @exception InstanceNotFoundException if the managed resource object + * cannot be found + * @exception MBeanException if the initializer of the object throws + * an exception, or persistence is not supported + * @exception RuntimeOperationsException if an exception is reported + * by the persistence mechanism + */ + public void store() throws InstanceNotFoundException, + MBeanException, RuntimeOperationsException { + + // XXX if a context was set, use it to store the data + throw new MBeanException + (new IllegalStateException("Persistence is not supported"), + "Persistence is not supported"); + + } + + // -------------------- BaseModelMBean methods -------------------- + + /** Set the type of the mbean. This is used as a key to locate + * the description in the Registry. + * + * @param type the type of classname of the modeled object + */ + public void setModeledType( String type ) { + initModelInfo(type); + createResource(); + } + /** Set the type of the mbean. This is used as a key to locate + * the description in the Registry. + * + * @param type the type of classname of the modeled object + */ + protected void initModelInfo( String type ) { + try { + if( log.isDebugEnabled()) + log.debug("setModeledType " + type); + + log.debug( "Set model Info " + type); + if(type==null) { + return; + } + resourceType=type; + //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader()); + Class c=null; + try { + c=Class.forName( type); + } catch( Throwable t ) { + log.debug( "Error creating class " + t); + } + + // The class c doesn't need to exist + ManagedBean descriptor=getRegistry().findManagedBean(c, type); + if( descriptor==null ) + return; + this.setModelMBeanInfo(descriptor.createMBeanInfo()); + } catch( Throwable ex) { + log.error( "TCL: " + Thread.currentThread().getContextClassLoader(), + ex); + } + } + + /** Set the type of the mbean. This is used as a key to locate + * the description in the Registry. + */ + protected void createResource() { + try { + //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader()); + Class c=null; + try { + c=Class.forName( resourceType ); + resource = c.newInstance(); + } catch( Throwable t ) { + log.error( "Error creating class " + t); + } + } catch( Throwable ex) { + log.error( "TCL: " + Thread.currentThread().getContextClassLoader(), + ex); + } + } + + + public String getModelerType() { + return resourceType; + } + + public String getClassName() { + return getModelerType(); + } + + public ObjectName getJmxName() { + return oname; + } + + public String getObjectName() { + if (oname != null) { + return oname.toString(); + } else { + return null; + } + } + + public void setRegistry(Registry registry) { + this.registry = registry; + } + + public Registry getRegistry() { + // XXX Need a better solution - to avoid the static + if( registry == null ) + registry=Registry.getRegistry(); + + return registry; + } + + // ------------------------------------------------------ Protected Methods + + + /** + * Create and return a default ModelMBeanInfo object. + */ + protected ModelMBeanInfo createDefaultModelMBeanInfo() { + + return (new ModelMBeanInfoSupport(this.getClass().getName(), + "Default ModelMBean", + null, null, null, null)); + + } + + /** + * Is the specified ModelMBeanInfo instance valid? + * + *

IMPLEMENTATION NOTE - This implementation + * does not check anything, but this method can be overridden + * as required.

+ * + * @param info The 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; + + +/** + *

Implementation of NotificationBroadcaster for attribute + * change notifications. This class is used by BaseModelMBean to + * handle notifications of attribute change events to interested listeners. + *

+ * + * @author Craig R. McClanahan + * @author Costin Manolache + */ + +public class BaseNotificationBroadcaster implements NotificationBroadcaster { + + + // ----------------------------------------------------------- Constructors + + + // ----------------------------------------------------- Instance Variables + + + /** + * The set of registered 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; iInternal configuration information for a Constructor + * descriptor.

+ * + * @author Craig R. McClanahan + * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ + */ + +public class ConstructorInfo extends FeatureInfo implements Serializable { + static final long serialVersionUID = -5735336213417238238L; + + // ----------------------------------------------------- Instance Variables + + + /** + * The 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.

+ * + * @author Craig R. McClanahan + * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ + */ + +public class FeatureInfo implements Serializable { + static final long serialVersionUID = -911529176124712296L; + protected String description = null; + protected List fields = new ArrayList(); + protected String name = null; + + // ------------------------------------------------------------- Properties + + + /** + * The human-readable description of this feature. + */ + public String getDescription() { + return (this.description); + } + + public void setDescription(String description) { + this.description = description; + } + + + /** + * The field information for this feature. + */ + public List getFields() { + return (fields); + } + + + /** + * The name of this feature, which must be unique among features in the + * same collection. + */ + public String getName() { + return (this.name); + } + + public void setName(String name) { + this.name = name; + } + + + // --------------------------------------------------------- Public Methods + + + /** + *

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.

+ * + * @param descriptor The 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:

+ *
    + *
  • Either the set of accepted names is empty (implying that all + * attribute names are of interest) or the set of accepted names + * includes the name of the attribute in this notification
  • + *
+ */ + public boolean isNotificationEnabled(Notification notification) { + + if (notification == null) + return (false); + synchronized (names) { + if (names.size() < 1) + return (true); + else + return (names.contains(notification.getType())); + } + + } + + +} diff --git a/java/org/apache/tomcat/util/modeler/JndiJmx.java b/java/org/apache/tomcat/util/modeler/JndiJmx.java new file mode 100644 index 000000000..988b5e14d --- /dev/null +++ b/java/org/apache/tomcat/util/modeler/JndiJmx.java @@ -0,0 +1,227 @@ +/* + * Copyright 2001-2002,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.Enumeration; +import java.util.Hashtable; + +import javax.management.AttributeChangeNotification; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.MBeanServerNotification; +import javax.management.Notification; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.naming.Context; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +// EXPERIMENTAL. It may fit better in tomcat jndi impl. + + +/** + * + * Link between JNDI and JMX. JNDI can be used for persistence ( it is + * an API for storing hierarchical data and a perfect fit for that ), as + * well as an alternate view of the MBean registry. + * + * If this component is enabled, all MBeans will be registered in JNDI, and + * all attributes that are set via JMX can be stored in a DirContext. + * + * This acts as a "recorder" for creation of mbeans and attribute changes + * done via JMX. + * + * XXX How can we control ( filter ) which mbeans will be registere ? Or + * attributes ? + * XXX How can we get the beans and attributes loaded before jndijmx ? + * + * The intended use: + * - do whatever you want to start the application + * - load JndiJmx as an mbean + * - make changes via JMX. All changes are recorded + * - you can use JndiJmx to save the changes in a Jndi context. + * - you can use JndiJmx to load changes from a JndiContext and replay them. + * + * The main benefit is that only changed attributes are saved, and the Jndi + * layer can preserve most of the original structure of the config file. The + * alternative is to override the config files with config info extracted + * from the live objects - but it's very hard to save only what was actually + * changed and preserve structure and comments. + * + * @author Costin Manolache + */ +public class JndiJmx extends BaseModelMBean implements NotificationListener { + + + private static Log log= LogFactory.getLog(JndiJmx.class); + + protected Context componentContext; + protected Context descriptorContext; + protected Context configContext; + + MBeanServer mserver; + + /** + * Protected constructor to require use of the factory create method. + */ + public JndiJmx() throws MBeanException { + super(JndiJmx.class.getName()); + } + + + /** If a JNDI context is set, all components + * will be registered in the context. + * + * @param ctx + */ + public void setComponentContext(Context ctx) { + this.componentContext= ctx; + } + + /** JNDI context for component descriptors ( metadata ). + * + * @param ctx + */ + public void setDescriptorContext(Context ctx) { + this.descriptorContext= ctx; + } + + /** JNDI context where attributes will be stored for persistence + * + */ + public void setConfigContext( Context ctx ) { + this.configContext= ctx; + } + + // -------------------- Registration/unregistration -------------------- + // temp - will only set in the jndi contexts + Hashtable attributes=new Hashtable(); + Hashtable instances=new Hashtable(); + + public void handleNotification(Notification notification, Object handback) + { + // register/unregister mbeans in jndi + if( notification instanceof MBeanServerNotification ) { + MBeanServerNotification msnot=(MBeanServerNotification)notification; + + ObjectName oname=msnot.getMBeanName(); + + if( "jmx.mbean.created".equalsIgnoreCase( notification.getType() )) { + try { + Object mbean=mserver.getObjectInstance(oname); + + if( log.isDebugEnabled() ) + log.debug( "MBean created " + oname + " " + mbean); + + // XXX add filter support + if( mbean instanceof NotificationBroadcaster ) { + // register for attribute changes + NotificationBroadcaster nb=(NotificationBroadcaster)mbean; + nb.addNotificationListener(this, null, null); + if( log.isDebugEnabled() ) + log.debug( "Add attribute change listener"); + } + + instances.put( oname.toString(), mbean ); + } catch( InstanceNotFoundException ex ) { + log.error( "Instance not found for the created object", ex ); + } + } + if( "jmx.mbean.deleted".equalsIgnoreCase( notification.getType() )) { + instances.remove(oname.toString()); + } + } + + // set attributes in jndi + // if( "jmx.attribute.changed".equals( notification.getType() )) { + if( notification instanceof AttributeChangeNotification) { + + AttributeChangeNotification anotif=(AttributeChangeNotification)notification; + String name=anotif.getAttributeName(); + Object value=anotif.getNewValue(); + Object source=anotif.getSource(); + String mname=null; + + Hashtable mbeanAtt=(Hashtable)attributes.get( source ); + if( mbeanAtt==null ) { + mbeanAtt=new Hashtable(); + attributes.put( source, mbeanAtt); + if( log.isDebugEnabled()) + log.debug("First attribute for " + source ); + } + mbeanAtt.put( name, anotif ); + + log.debug( "Attribute change notification " + name + " " + value + " " + source ); + + } + + } + + public String dumpStatus() throws Exception + { + StringBuffer sb=new StringBuffer(); + Enumeration en=instances.keys(); + while (en.hasMoreElements()) { + String on = (String) en.nextElement(); + Object mbean=instances.get(on); + Hashtable mbeanAtt=(Hashtable)attributes.get(mbean); + + sb.append( ""); + sb.append( "\n"); + Enumeration attEn=mbeanAtt.keys(); + while (attEn.hasMoreElements()) { + String an = (String) attEn.nextElement(); + AttributeChangeNotification anotif= + (AttributeChangeNotification)mbeanAtt.get(an); + sb.append(" "); + sb.append( "\n"); + } + + + sb.append( ""); + sb.append( "\n"); + } + return sb.toString(); + } + + public void replay() throws Exception + { + + + } + + + public void init() throws Exception + { + + MBeanServer mserver=(MBeanServer)Registry.getRegistry().getMBeanServer(); + ObjectName delegate=new ObjectName("JMImplementation:type=MBeanServerDelegate"); + + // XXX need to extract info about previously loaded beans + + // we'll know of all registered beans + mserver.addNotificationListener(delegate, this, null, null ); + + } + +} diff --git a/java/org/apache/tomcat/util/modeler/ManagedBean.java b/java/org/apache/tomcat/util/modeler/ManagedBean.java new file mode 100644 index 000000000..a2c39a74d --- /dev/null +++ b/java/org/apache/tomcat/util/modeler/ManagedBean.java @@ -0,0 +1,508 @@ +/* + * 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 java.util.List; + +import javax.management.Descriptor; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.RuntimeOperationsException; +import javax.management.modelmbean.InvalidTargetObjectTypeException; +import javax.management.modelmbean.ModelMBean; +import javax.management.modelmbean.ModelMBeanAttributeInfo; +import javax.management.modelmbean.ModelMBeanConstructorInfo; +import javax.management.modelmbean.ModelMBeanInfo; +import javax.management.modelmbean.ModelMBeanInfoSupport; +import javax.management.modelmbean.ModelMBeanNotificationInfo; +import javax.management.modelmbean.ModelMBeanOperationInfo; + + +/** + *

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 + + + /** + * The ModelMBeanInfo 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.

+ */ + public List getFields() { + return (this.fields); + } + + + /** + * The (optional) group to which this MBean belongs. + */ + public String getGroup() { + return (this.group); + } + + public void setGroup(String group) { + this.group = group; + } + + + /** + * The name of this managed bean, which must be unique among all + * MBeans managed by a particular MBeans server. + */ + public String getName() { + return (this.name); + } + + public void setName(String name) { + this.name = name; + this.info = null; + } + + + /** + * The collection of notifications for this MBean. + */ + public NotificationInfo[] getNotifications() { + return (this.notifications); + } + + + /** + * The collection of operations for this MBean. + */ + public OperationInfo[] getOperations() { + return (this.operations); + } + + + /** + * The fully qualified name of the Java class of the resource + * implementation class described by the managed bean described + * by this descriptor. + */ + public String getType() { + return (this.type); + } + + public void setType(String type) { + this.type = type; + this.info = null; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new attribute to the set of attributes for this MBean. + * + * @param attribute The new attribute descriptor + */ + public void addAttribute(AttributeInfo attribute) { + + synchronized (attributes) { + AttributeInfo results[] = + new AttributeInfo[attributes.length + 1]; + System.arraycopy(attributes, 0, results, 0, attributes.length); + results[attributes.length] = attribute; + attributes = results; + this.info = null; + } + + } + + + /** + * Add a new constructor to the set of constructors for this MBean. + * + * @param constructor The new constructor descriptor + */ + public void addConstructor(ConstructorInfo constructor) { + + synchronized (constructors) { + ConstructorInfo results[] = + new ConstructorInfo[constructors.length + 1]; + System.arraycopy(constructors, 0, results, 0, constructors.length); + results[constructors.length] = constructor; + constructors = results; + this.info = null; + } + + } + + + /** + *

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 a ModelMBean 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.

+ * + * @author Craig R. McClanahan + * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ + */ + +public class NotificationInfo extends FeatureInfo implements Serializable { + static final long serialVersionUID = -6319885418912650856L; + + // ----------------------------------------------------- Instance Variables + + + /** + * The 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.

+ * + * @author Craig R. McClanahan + * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ + */ + +public class OperationInfo extends FeatureInfo implements Serializable { + static final long serialVersionUID = 4418342922072614875L; + // ----------------------------------------------------------- Constructors + + + /** + * Standard zero-arguments constructor. + */ + public OperationInfo() { + + super(); + + } + + + /** + * Special constructor for setting up getter and setter operations. + * + * @param name Name of this operation + * @param getter Is this a getter (as opposed to a setter)? + * @param type Data type of the return value (if this is a getter) + * or the parameter (if this is a setter) + * + */ + public OperationInfo(String name, boolean getter, String type) { + + super(); + setName(name); + if (getter) { + setDescription("Attribute getter method"); + setImpact("INFO"); + setReturnType(type); + setRole("getter"); + } else { + setDescription("Attribute setter method"); + setImpact("ACTION"); + setReturnType("void"); + setRole("setter"); + addParameter(new ParameterInfo("value", type, + "New attribute value")); + } + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The 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.

+ * + * @author Craig R. McClanahan + * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ + */ + +public class ParameterInfo extends FeatureInfo implements Serializable { + static final long serialVersionUID = 2222796006787664020L; + // ----------------------------------------------------------- Constructors + + + /** + * Standard zero-arguments constructor. + */ + public ParameterInfo() { + + super(); + + } + + + /** + * Special constructor for setting up parameters programatically. + * + * @param name Name of this parameter + * @param type Java class of this parameter + * @param description Description of this parameter + */ + public ParameterInfo(String name, String type, String description) { + + super(); + setName(name); + setType(type); + setDescription(description); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The 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
instance. + * + */ + public synchronized MBeanServer getMBeanServer() { + long t1=System.currentTimeMillis(); + + if (server == null) { + if( MBeanServerFactory.findMBeanServer(null).size() > 0 ) { + server=(MBeanServer)MBeanServerFactory.findMBeanServer(null).get(0); + if( log.isDebugEnabled() ) { + log.debug("Using existing MBeanServer " + (System.currentTimeMillis() - t1 )); + } + } else { + server=MBeanServerFactory.createMBeanServer(); + if( log.isDebugEnabled() ) { + log.debug("Creating MBeanServer"+ (System.currentTimeMillis() - t1 )); + } + } + } + return (server); + } + + /** Find or load metadata. + */ + public ManagedBean findManagedBean(Object bean, Class beanClass, String type) + throws Exception + { + if( bean!=null && beanClass==null ) { + beanClass=bean.getClass(); + } + + if( type==null ) { + type=beanClass.getName(); + } + + // first look for existing descriptor + ManagedBean managed = findManagedBean(type); + + // Search for a descriptor in the same package + if( managed==null ) { + // check package and parent packages + if( log.isDebugEnabled() ) { + log.debug( "Looking for descriptor "); + } + findDescriptor( beanClass, type ); + + managed=findManagedBean(type); + } + + if( bean instanceof DynamicMBean ) { + if( log.isDebugEnabled() ) { + log.debug( "Dynamic mbean support "); + } + // Dynamic mbean + loadDescriptors("MbeansDescriptorsDynamicMBeanSource", + bean, type); + + managed=findManagedBean(type); + } + + // Still not found - use introspection + if( managed==null ) { + if( log.isDebugEnabled() ) { + log.debug( "Introspecting "); + } + + // introspection + loadDescriptors("MbeansDescriptorsIntrospectionSource", + beanClass, type); + + managed=findManagedBean(type); + if( managed==null ) { + log.warn( "No metadata found for " + type ); + return null; + } + managed.setName( type ); + addManagedBean(managed); + } + return managed; + } + + + /** EXPERIMENTAL Convert a string to object, based on type. Used by several + * components. We could provide some pluggability. It is here to keep + * things consistent and avoid duplication in other tasks + * + * @param type Fully qualified class name of the resulting value + * @param value String value to be converted + * @return Converted value + */ + public Object convertValue(String type, String value) + { + Object objValue=value; + + if( type==null || "java.lang.String".equals( type )) { + // string is default + objValue=value; + } else if( "javax.management.ObjectName".equals( type ) || + "ObjectName".equals( type )) { + try { + objValue=new ObjectName( value ); + } catch (MalformedObjectNameException e) { + return null; + } + } else if( "java.lang.Integer".equals( type ) || + "int".equals( type )) { + objValue=new Integer( value ); + } else if( "java.lang.Boolean".equals( type ) || + "boolean".equals( type )) { + objValue=new Boolean( value ); + } + return objValue; + } + + /** Experimental. + * + * @param sourceType + * @param source + * @param param + * @return List of descriptors + * @throws Exception + * @deprecated bad interface, mixing of metadata and mbeans + */ + public List load( String sourceType, Object source, String param) + throws Exception + { + if( log.isTraceEnabled()) { + log.trace("load " + source ); + } + String location=null; + String type=null; + Object inputsource=null; + + if( source instanceof DynamicMBean ) { + sourceType="MbeansDescriptorsDynamicMBeanSource"; + inputsource=source; + } else if( source instanceof URL ) { + URL url=(URL)source; + location=url.toString(); + type=param; + inputsource=url.openStream(); + if( sourceType == null ) { + sourceType = sourceTypeFromExt(location); + } + } else if( source instanceof File ) { + location=((File)source).getAbsolutePath(); + inputsource=new FileInputStream((File)source); + type=param; + if( sourceType == null ) { + sourceType = sourceTypeFromExt(location); + } + } else if( source instanceof InputStream ) { + type=param; + inputsource=source; + } else if( source instanceof Class ) { + location=((Class)source).getName(); + type=param; + inputsource=source; + if( sourceType== null ) { + sourceType="MbeansDescriptorsIntrospectionSource"; + } + } + + if( sourceType==null ) { + sourceType="MbeansDescriptorsDOMSource"; + } + ModelerSource ds=getModelerSource(sourceType); + List mbeans=ds.loadDescriptors(this, location, type, inputsource); + + return mbeans; + } + + private String sourceTypeFromExt( String s ) { + if( s.endsWith( ".ser")) { + return "MbeansDescriptorsSerSource"; + } + else if( s.endsWith(".xml")) { + return "MbeansDescriptorsDOMSource"; + } + return null; + } + + /** Register a component + * XXX make it private + * + * @param bean + * @param oname + * @param type + * @throws Exception + */ + public void registerComponent(Object bean, ObjectName oname, String type) + throws Exception + { + if( log.isDebugEnabled() ) { + log.debug( "Managed= "+ oname); + } + + if( bean ==null ) { + log.error("Null component " + oname ); + return; + } + + try { + if( type==null ) { + type=bean.getClass().getName(); + } + + ManagedBean managed = findManagedBean(bean.getClass(), type); + + // The real mbean is created and registered + ModelMBean mbean = managed.createMBean(bean); + + if( getMBeanServer().isRegistered( oname )) { + if( log.isDebugEnabled()) { + log.debug("Unregistering existing component " + oname ); + } + getMBeanServer().unregisterMBean( oname ); + } + + getMBeanServer().registerMBean( mbean, oname); + } catch( Exception ex) { + log.error("Error registering " + oname, ex ); + throw ex; + } + } + + /** Lookup the component descriptor in the package and + * in the parent packages. + * + * @param packageName + */ + public void loadDescriptors( String packageName, ClassLoader classLoader ) { + String res=packageName.replace( '.', '/'); + + if( log.isTraceEnabled() ) { + log.trace("Finding descriptor " + res ); + } + + if( searchedPaths.get( packageName ) != null ) { + return; + } + String descriptors=res + "/mbeans-descriptors.ser"; + + URL dURL=classLoader.getResource( descriptors ); + + if( dURL == null ) { + descriptors=res + "/mbeans-descriptors.xml"; + dURL=classLoader.getResource( descriptors ); + } + if( dURL == null ) { + return; + } + + log.debug( "Found " + dURL); + searchedPaths.put( packageName, dURL ); + try { + if( descriptors.endsWith(".xml" )) + loadDescriptors("MbeansDescriptorsDOMSource", dURL, null); + else + loadDescriptors("MbeansDescriptorsSerSource", dURL, null); + return; + } catch(Exception ex ) { + log.error("Error loading " + dURL); + } + + return; + } + + /** Experimental. Will become private, some code may still use it + * + * @param sourceType + * @param source + * @param param + * @throws Exception + * @deprecated + */ + public void loadDescriptors( String sourceType, Object source, String param) + throws Exception + { + List mbeans=load( sourceType, source, param ); + if( mbeans == null) return; + + Iterator itr=mbeans.iterator(); + while( itr.hasNext() ) { + Object mb=itr.next(); + if( mb instanceof ManagedBean) { + addManagedBean((ManagedBean)mb); + } + } + } + + /** Discover all META-INF/modeler.xml files in classpath and register + * the components + * + * @since EXPERIMENTAL + */ + private void loadMetaInfDescriptors(ClassLoader cl) { + try { + Enumeration en=cl.getResources(MODELER_MANIFEST); + while( en.hasMoreElements() ) { + URL url=(URL)en.nextElement(); + InputStream is=url.openStream(); + if( log.isDebugEnabled()) log.debug("Loading " + url); + loadDescriptors("MBeansDescriptorDOMSource", is, null ); + } + } catch( Exception ex ) { + ex.printStackTrace(); + } + } + + /** Lookup the component descriptor in the package and + * in the parent packages. + * + * @param beanClass + * @param type + */ + private void findDescriptor( Class beanClass, String type ) { + if( type==null ) { + type=beanClass.getName(); + } + ClassLoader classLoader=null; + if( beanClass!=null ) { + classLoader=beanClass.getClassLoader(); + } + if( classLoader==null ) { + classLoader=Thread.currentThread().getContextClassLoader(); + } + if( classLoader==null ) { + classLoader=this.getClass().getClassLoader(); + } + + String className=type; + String pkg=className; + while( pkg.indexOf( ".") > 0 ) { + int lastComp=pkg.lastIndexOf( "."); + if( lastComp <= 0 ) return; + pkg=pkg.substring(0, lastComp); + if( searchedPaths.get( pkg ) != null ) { + return; + } + loadDescriptors(pkg, classLoader); + } + return; + } + + private ModelerSource getModelerSource( String type ) + throws Exception + { + if( type==null ) type="MbeansDescriptorsDOMSource"; + if( type.indexOf( ".") < 0 ) { + type="org.apache.tomcat.util.modeler.modules." + type; + } + + Class c=Class.forName( type ); + ModelerSource ds=(ModelerSource)c.newInstance(); + return ds; + } + + + // -------------------- Registration -------------------- + + public ObjectName preRegister(MBeanServer server, + ObjectName name) throws Exception + { + this.server=server; + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + + + + + // -------------------- DEPRECATED METHODS -------------------- + // May still be used in tomcat + // Never part of an official release + + /** Called by a registry or by the container to unload a loader + * @param loader + */ + public void unregisterRegistry(ClassLoader loader ) { + // XXX Cleanup ? + perLoaderRegistries.remove(loader); + } + + public ManagedBean findManagedBean(Class beanClass, String type) + throws Exception + { + return findManagedBean(null, beanClass, type); + } + + /** + * Set the MBeanServer 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 element + for (Node mbeanN = firstMbeanN; mbeanN != null; + mbeanN= DomUtil.getNext(mbeanN)) + { + + // Create a new managed bean info + ManagedBean managed=new ManagedBean(); + DomUtil.setAttributes(managed, mbeanN); + Node firstN; + + // Process descriptor subnode + Node mbeanDescriptorN = + DomUtil.getChild(mbeanN, "descriptor"); + if (mbeanDescriptorN != null) { + Node firstFieldN = + DomUtil.getChild(mbeanDescriptorN, "field"); + for (Node fieldN = firstFieldN; fieldN != null; + fieldN = DomUtil.getNext(fieldN)) { + FieldInfo fi = new FieldInfo(); + DomUtil.setAttributes(fi, fieldN); + managed.addField(fi); + } + } + + // process attribute nodes + firstN=DomUtil.getChild( mbeanN, "attribute"); + for (Node descN = firstN; descN != null; + descN = DomUtil.getNext( descN )) + { + + // Create new attribute info + AttributeInfo ai=new AttributeInfo(); + DomUtil.setAttributes(ai, descN); + + // Process descriptor subnode + Node descriptorN = + DomUtil.getChild(descN, "descriptor"); + if (descriptorN != null) { + Node firstFieldN = + DomUtil.getChild(descriptorN, "field"); + for (Node fieldN = firstFieldN; fieldN != null; + fieldN = DomUtil.getNext(fieldN)) { + FieldInfo fi = new FieldInfo(); + DomUtil.setAttributes(fi, fieldN); + ai.addField(fi); + } + } + + // Add this info to our managed bean info + managed.addAttribute( ai ); + if (log.isTraceEnabled()) { + log.trace("Create attribute " + ai); + } + + } + + // process constructor nodes + firstN=DomUtil.getChild( mbeanN, "constructor"); + for (Node descN = firstN; descN != null; + descN = DomUtil.getNext( descN )) { + + // Create new constructor info + ConstructorInfo ci=new ConstructorInfo(); + DomUtil.setAttributes(ci, descN); + + // Process descriptor subnode + Node firstDescriptorN = + DomUtil.getChild(descN, "descriptor"); + if (firstDescriptorN != null) { + Node firstFieldN = + DomUtil.getChild(firstDescriptorN, "field"); + for (Node fieldN = firstFieldN; fieldN != null; + fieldN = DomUtil.getNext(fieldN)) { + FieldInfo fi = new FieldInfo(); + DomUtil.setAttributes(fi, fieldN); + ci.addField(fi); + } + } + + // Process parameter subnodes + Node firstParamN=DomUtil.getChild( descN, "parameter"); + for (Node paramN = firstParamN; paramN != null; + paramN = DomUtil.getNext(paramN)) + { + ParameterInfo pi=new ParameterInfo(); + DomUtil.setAttributes(pi, paramN); + ci.addParameter( pi ); + } + + // Add this info to our managed bean info + managed.addConstructor( ci ); + if (log.isTraceEnabled()) { + log.trace("Create constructor " + ci); + } + + } + + // process notification nodes + firstN=DomUtil.getChild( mbeanN, "notification"); + for (Node descN = firstN; descN != null; + descN = DomUtil.getNext( descN )) + { + + // Create new notification info + NotificationInfo ni=new NotificationInfo(); + DomUtil.setAttributes(ni, descN); + + // Process descriptor subnode + Node firstDescriptorN = + DomUtil.getChild(descN, "descriptor"); + if (firstDescriptorN != null) { + Node firstFieldN = + DomUtil.getChild(firstDescriptorN, "field"); + for (Node fieldN = firstFieldN; fieldN != null; + fieldN = DomUtil.getNext(fieldN)) { + FieldInfo fi = new FieldInfo(); + DomUtil.setAttributes(fi, fieldN); + ni.addField(fi); + } + } + + // Process notification-type subnodes + Node firstParamN=DomUtil.getChild( descN, "notification-type"); + for (Node paramN = firstParamN; paramN != null; + paramN = DomUtil.getNext(paramN)) + { + ni.addNotifType( DomUtil.getContent(paramN) ); + } + + // Add this info to our managed bean info + managed.addNotification( ni ); + if (log.isTraceEnabled()) { + log.trace("Created notification " + ni); + } + + } + + // process operation nodes + firstN=DomUtil.getChild( mbeanN, "operation"); + for (Node descN = firstN; descN != null; + descN = DomUtil.getNext( descN )) + + { + + // Create new operation info + OperationInfo oi=new OperationInfo(); + DomUtil.setAttributes(oi, descN); + + // Process descriptor subnode + Node firstDescriptorN = + DomUtil.getChild(descN, "descriptor"); + if (firstDescriptorN != null) { + Node firstFieldN = + DomUtil.getChild(firstDescriptorN, "field"); + for (Node fieldN = firstFieldN; fieldN != null; + fieldN = DomUtil.getNext(fieldN)) { + FieldInfo fi = new FieldInfo(); + DomUtil.setAttributes(fi, fieldN); + oi.addField(fi); + } + } + + // Process parameter subnodes + Node firstParamN=DomUtil.getChild( descN, "parameter"); + for (Node paramN = firstParamN; paramN != null; + paramN = DomUtil.getNext(paramN)) + { + ParameterInfo pi=new ParameterInfo(); + DomUtil.setAttributes(pi, paramN); + if( log.isTraceEnabled()) + log.trace("Add param " + pi.getName()); + oi.addParameter( pi ); + } + + // Add this info to our managed bean info + managed.addOperation( oi ); + if( log.isTraceEnabled()) { + log.trace("Create operation " + oi); + } + + } + + // Add the completed managed bean info to the registry + //registry.addManagedBean(managed); + mbeans.add( managed ); + + } + + long t2=System.currentTimeMillis(); + log.debug( "Reading descriptors ( dom ) " + (t2-t1)); + } catch( Exception ex ) { + log.error( "Error reading descriptors ", ex); + } + } +} diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java new file mode 100644 index 000000000..901926a78 --- /dev/null +++ b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java @@ -0,0 +1,228 @@ +/* + * 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.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.modeler.Registry; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class MbeansDescriptorsDigesterSource extends ModelerSource +{ + private static Log log = + LogFactory.getLog(MbeansDescriptorsDigesterSource.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(); + + InputStream stream=(InputStream)source; + + long t1=System.currentTimeMillis(); + + Digester digester = new Digester(); + digester.setNamespaceAware(false); + digester.setValidating(false); + URL url = registry.getClass().getResource + ("/org/apache/commons/modeler/mbeans-descriptors.dtd"); + digester.register + ("-//Apache Software Foundation//DTD Model MBeans Configuration File", + url.toString()); + + // Push our registry object onto the stack + digester.push(mbeans); + + // Configure the parsing rules + digester.addObjectCreate + ("mbeans-descriptors/mbean", + "org.apache.tomcat.util.modeler.ManagedBean"); + digester.addSetProperties + ("mbeans-descriptors/mbean"); + digester.addSetNext + ("mbeans-descriptors/mbean", + "add", + "java.lang.Object"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/attribute", + "org.apache.tomcat.util.modeler.AttributeInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/attribute"); + digester.addSetNext + ("mbeans-descriptors/mbean/attribute", + "addAttribute", + "org.apache.tomcat.util.modeler.AttributeInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/attribute/descriptor/field", + "org.apache.tomcat.util.modeler.FieldInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/attribute/descriptor/field"); + digester.addSetNext + ("mbeans-descriptors/mbean/attribute/descriptor/field", + "addField", + "org.apache.tomcat.util.modeler.FieldInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/constructor", + "org.apache.tomcat.util.modeler.ConstructorInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/constructor"); + digester.addSetNext + ("mbeans-descriptors/mbean/constructor", + "addConstructor", + "org.apache.tomcat.util.modeler.ConstructorInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/constructor/descriptor/field", + "org.apache.tomcat.util.modeler.FieldInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/constructor/descriptor/field"); + digester.addSetNext + ("mbeans-descriptors/mbean/constructor/descriptor/field", + "addField", + "org.apache.tomcat.util.modeler.FieldInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/constructor/parameter", + "org.apache.tomcat.util.modeler.ParameterInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/constructor/parameter"); + digester.addSetNext + ("mbeans-descriptors/mbean/constructor/parameter", + "addParameter", + "org.apache.tomcat.util.modeler.ParameterInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/descriptor/field", + "org.apache.tomcat.util.modeler.FieldInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/descriptor/field"); + digester.addSetNext + ("mbeans-descriptors/mbean/descriptor/field", + "addField", + "org.apache.tomcat.util.modeler.FieldInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/notification", + "org.apache.tomcat.util.modeler.NotificationInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/notification"); + digester.addSetNext + ("mbeans-descriptors/mbean/notification", + "addNotification", + "org.apache.tomcat.util.modeler.NotificationInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/notification/descriptor/field", + "org.apache.tomcat.util.modeler.FieldInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/notification/descriptor/field"); + digester.addSetNext + ("mbeans-descriptors/mbean/notification/descriptor/field", + "addField", + "org.apache.tomcat.util.modeler.FieldInfo"); + + digester.addCallMethod + ("mbeans-descriptors/mbean/notification/notification-type", + "addNotifType", 0); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/operation", + "org.apache.tomcat.util.modeler.OperationInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/operation"); + digester.addSetNext + ("mbeans-descriptors/mbean/operation", + "addOperation", + "org.apache.tomcat.util.modeler.OperationInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/operation/descriptor/field", + "org.apache.tomcat.util.modeler.FieldInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/operation/descriptor/field"); + digester.addSetNext + ("mbeans-descriptors/mbean/operation/descriptor/field", + "addField", + "org.apache.tomcat.util.modeler.FieldInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/operation/parameter", + "org.apache.tomcat.util.modeler.ParameterInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/operation/parameter"); + digester.addSetNext + ("mbeans-descriptors/mbean/operation/parameter", + "addParameter", + "org.apache.tomcat.util.modeler.ParameterInfo"); + + // Process the input file to configure our registry + try { + digester.parse(stream); + } catch (Exception e) { + log.error("Error digesting Registry data", e); + throw e; + } + long t2=System.currentTimeMillis(); +// if( t2-t1 > 500 ) + log.info("Loaded registry information (digester) " + ( t2 - t1 ) + " ms"); + } +} diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDynamicMBeanSource.java b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDynamicMBeanSource.java new file mode 100644 index 000000000..5aa2ff75b --- /dev/null +++ b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDynamicMBeanSource.java @@ -0,0 +1,157 @@ +package org.apache.tomcat.util.modeler.modules; + +import java.util.ArrayList; +import java.util.List; + +import javax.management.DynamicMBean; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.modeler.AttributeInfo; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.OperationInfo; +import org.apache.tomcat.util.modeler.ParameterInfo; +import org.apache.tomcat.util.modeler.Registry; + + +/** Extract metadata from a dynamic mbean. + * Used to wrap a dynamic mbean in order to implement persistence. + * + * This is really an ugly asspect of the JMX spec - we need to convery + * from normal metainfo to model metainfo. The info is the same, but + * they use a different class. Just like the DOM spec - where all implementations + * get an order of unneeded complexity from the various types. + * + */ +public class MbeansDescriptorsDynamicMBeanSource extends ModelerSource +{ + private static Log log = LogFactory.getLog(MbeansDescriptorsDynamicMBeanSource.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 { + ManagedBean managed=createManagedBean(registry, null, source, type); + if( managed==null ) return; + managed.setName( type ); + + mbeans.add(managed); + + } catch( Exception ex ) { + log.error( "Error reading descriptors ", ex); + } + } + + + + // ------------ Implementation for non-declared introspection classes + + + /** + * XXX Find if the 'className' is the name of the MBean or + * the real class ( I suppose first ) + * XXX Read (optional) descriptions from a .properties, generated + * from source + * XXX Deal with constructors + * + */ + public ManagedBean createManagedBean(Registry registry, String domain, + Object realObj, String type) + { + if( ! ( realObj instanceof DynamicMBean )) { + return null; + } + DynamicMBean dmb=(DynamicMBean)realObj; + + ManagedBean mbean= new ManagedBean(); + + MBeanInfo mbi=dmb.getMBeanInfo(); + + try { + MBeanAttributeInfo attInfo[]=mbi.getAttributes(); + for( int i=0; i updateInterval ) { + lastUpdate=time; + try { + FileOutputStream fos=new FileOutputStream(location); + DomUtil.writeXml(document, fos); + } catch (TransformerException e) { + log.error( "Error writing"); + } catch (FileNotFoundException e) { + log.error( "Error writing" ,e ); + } + } + } + + private void processAttribute(MBeanServer server, + Node descN, String objectName ) { + String attName=DomUtil.getAttribute(descN, "name"); + String value=DomUtil.getAttribute(descN, "value"); + String type=null; // DomUtil.getAttribute(descN, "type"); + if( value==null ) { + // The value may be specified as CDATA + value=DomUtil.getContent(descN); + } + try { + if( log.isDebugEnabled()) + log.debug("Set attribute " + objectName + " " + attName + + " " + value); + ObjectName oname=new ObjectName(objectName); + // find the type + if( type==null ) + type=registry.getType( oname, attName ); + + if( type==null ) { + log.info("Can't find attribute " + objectName + " " + attName ); + + } else { + Object valueO=registry.convertValue( type, value); + server.setAttribute(oname, new Attribute(attName, valueO)); + } + } catch( Exception ex) { + log.error("Error processing attribute " + objectName + " " + + attName + " " + value, ex); + } + + } + + private void processArg(Node mbeanN) { + Node firstArgN=DomUtil.getChild(mbeanN, "arg" ); + // process all args + for (Node argN = firstArgN; argN != null; + argN = DomUtil.getNext( argN )) + { + String type=DomUtil.getAttribute(argN, "type"); + String value=DomUtil.getAttribute(argN, "value"); + if( value==null ) { + // The value may be specified as CDATA + value=DomUtil.getContent(argN); + } + } + } +} diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansSourceMBean.java b/java/org/apache/tomcat/util/modeler/modules/MbeansSourceMBean.java new file mode 100644 index 000000000..c577d842c --- /dev/null +++ b/java/org/apache/tomcat/util/modeler/modules/MbeansSourceMBean.java @@ -0,0 +1,42 @@ +package org.apache.tomcat.util.modeler.modules; + +import java.util.List; + + +/** + * This mbean will load an extended mlet file ( similar in syntax with jboss ). + * It'll keep track of all attribute changes and update the file when attributes + * change. + */ +public interface MbeansSourceMBean +{ + /** Set the source to be used to load the mbeans + * + * @param source File or URL + */ + public void setSource( Object source ); + + public Object getSource(); + + /** Return the list of loaded mbeans names + * + * @return List of ObjectName + */ + public List getMBeans(); + + /** Load the mbeans from the source. Called automatically on init() + * + * @throws Exception + */ + public void load() throws Exception; + + /** Call the init method on all mbeans. Will call load if not done already + * + * @throws Exception + */ + public void init() throws Exception; + + /** Save the file. + */ + public void save(); +} diff --git a/java/org/apache/tomcat/util/modeler/modules/ModelerSource.java b/java/org/apache/tomcat/util/modeler/modules/ModelerSource.java new file mode 100644 index 000000000..35f21c891 --- /dev/null +++ b/java/org/apache/tomcat/util/modeler/modules/ModelerSource.java @@ -0,0 +1,70 @@ +package org.apache.tomcat.util.modeler.modules; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.List; + +import javax.management.ObjectName; + +import org.apache.tomcat.util.modeler.Registry; + +/** Source for descriptor data. More sources can be added. + * + */ +public class ModelerSource { + protected Object source; + protected String location; + + /** Load data, returns a list of items. + * + * @param registry + * @param location + * @param type + * @param source Introspected object or some other source + * @throws Exception + */ + public List loadDescriptors( Registry registry, String location, + String type, Object source) + throws Exception + { + // TODO + return null; + } + + /** Callback from the BaseMBean to notify that an attribute has changed. + * Can be used to implement persistence. + * + * @param oname + * @param name + * @param value + */ + public void updateField( ObjectName oname, String name, + Object value ) { + // nothing by default + } + + public void store() { + // nothing + } + + protected InputStream getInputStream() throws IOException { + if( source instanceof URL ) { + URL url=(URL)source; + location=url.toString(); + return url.openStream(); + } else if( source instanceof File ) { + location=((File)source).getAbsolutePath(); + return new FileInputStream((File)source); + } else if( source instanceof String) { + location=(String)source; + return new FileInputStream((String)source); + } else if( source instanceof InputStream ) { + return (InputStream)source; + } + return null; + } + +} diff --git a/java/org/apache/tomcat/util/modeler/modules/package.html b/java/org/apache/tomcat/util/modeler/modules/package.html new file mode 100644 index 000000000..7f1574d42 --- /dev/null +++ b/java/org/apache/tomcat/util/modeler/modules/package.html @@ -0,0 +1,43 @@ + + +org.apache.commons.modeler.modules + + +

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 @@ + + +Package Documentation for COMMONS-MODELER + + +

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).

. More advanced uses can +be found in Tomcat 5 and jakarta-tomcat-connectors. + + +

1. Acquire a JMX Implementation

+ +

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.

+ + +

2. Create a Modeler Configuration File

+ +

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.

+ + +

3. Create Modeler Registry at Startup Time

+ +

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

+ + +

4. Instantiate Model MBeans As Needed

+ +

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