donaldp 2002/07/30 05:31:17 Modified: . build.xml src/java/org/apache/avalon/phoenix/components/application ExportHelper.java Resources.properties src/java/org/apache/avalon/phoenix/components/embeddor DefaultEmbeddor.java src/java/org/apache/avalon/phoenix/components/kernel DefaultApplicationContext.java src/java/org/apache/avalon/phoenix/components/manager AbstractJMXManager.java MX4JSystemManager.java Resources.properties SubContext.java src/java/org/apache/avalon/phoenix/interfaces ApplicationContext.java SystemManager.java Added: src/java/org/apache/avalon/phoenix/components/manager MBeanInfoBuilder.java Target.java Log: Rework the Management subsystem so that it is capable of exporting mbeans to MBeanServer if they have a coresponding mxinfo descriptor beside either themselves or their services. See mailing list for further details. Submitted by: Huw Roberts <[EMAIL PROTECTED]> Revision Changes Path 1.143 +41 -48 jakarta-avalon-phoenix/build.xml Index: build.xml =================================================================== RCS file: /home/cvs/jakarta-avalon-phoenix/build.xml,v retrieving revision 1.142 retrieving revision 1.143 diff -u -r1.142 -r1.143 --- build.xml 15 Jul 2002 15:54:19 -0000 1.142 +++ build.xml 30 Jul 2002 12:31:16 -0000 1.143 @@ -38,6 +38,7 @@ <property name="build.src" value="${build.dir}/src"/> <property name="build.classes" value="${build.dir}/classes"/> <property name="build.reports" value="${build.dir}/reports"/> + <property name="build.xdoclet" value="${build.dir}/xdoclet"/> <!-- Set the properties for source directories --> <property name="src.dir" value="src"/> @@ -59,16 +60,12 @@ <property name="xalan.jar" value="${lib.dir}/xalan-2.3.1.jar"/> <property name="framework.jar" value="${lib.dir}/avalon-framework-20020713.jar"/> <property name="logkit.jar" value="${lib.dir}/logkit-1.1a.jar"/> - <property name="jmxri.jar" value="${lib.dir}/jmxri.jar"/> - <property name="jmxtools.jar" value="${lib.dir}/jmxtools.jar"/> <property name="tools.jar" value="${java.home}/../lib/tools.jar"/> <path id="project.class.path"> <pathelement location="${xerces.jar}"/> <pathelement location="${framework.jar}"/> <pathelement location="${logkit.jar}"/> - <pathelement location="${jmxri.jar}"/> - <pathelement location="${jmxtools.jar}"/> <pathelement location="${wrapper.jar}"/> <pathelement path="${mx4j.jar}"/> <pathelement path="${mx4j-tools.jar}"/> @@ -105,7 +102,6 @@ <available property="servlet.present" classname="javax.servlet.Servlet"> <classpath refid="project.class.path"/> </available> - <available property="jmx-ri.present" file="${jmxri.jar}"/> <available property="jmx.present" classname="javax.management.MBeanException"> <classpath refid="project.class.path"/> </available> @@ -185,10 +181,12 @@ unless="jmx.present"/> <exclude name="org/apache/avalon/phoenix/components/manager/rmiadaptor/*.java" unless="jmx.present"/> + <exclude name="org/apache/avalon/phoenix/components/manager/Target.java" + unless="jmx.present"/> + <exclude name="org/apache/avalon/phoenix/components/manager/MBeanInfoBuilder.java" + unless="jmx.present"/> <exclude name="org/apache/avalon/phoenix/components/manager/MX4JSystemManager.java" unless="mx4j.present"/> - <exclude name="org/apache/avalon/phoenix/components/manager/DefaultManager.java" - unless="jmx-ri.present"/> <exclude name="org/apache/avalon/phoenix/launcher/DaemonLauncher.java" unless="wrapper.present"/> <exclude name="org/apache/avalon/phoenix/components/kernel/beanshell/*.java" @@ -204,19 +202,29 @@ </target> - <target name="rmic" depends="compile" if="jmx.present" - description="runs rmic on JMX Adaptor"> + <!-- Make .xinfo, .mxinfo and manifest automatically for blocks --> + <target name="phoenix-xdoclet" depends="compile"> - <rmic base="${build.classes}" - classname="org.apache.avalon.phoenix.components.manager.rmiadaptor.RMIAdaptorImpl" - stubVersion="1.2"> - <classpath refid="project.class.path" /> - </rmic> + <mkdir dir="${build.xdoclet}"/> - </target> + <taskdef name="phoenix-blocks" + classname="org.apache.avalon.phoenix.tools.xdoclet.PhoenixXDoclet" + classpathref="project.class.path"/> + + <phoenix-blocks + destdir="${build.xdoclet}" + classpathref="project.class.path"> + <fileset dir="${java.dir}"> + <include name="**" /> + </fileset> + <blockinfo/> + <mxinfo/> + </phoenix-blocks> + + </target> <!-- Creates all the .jar files --> - <target name="jars" depends="rmic"> + <target name="jars" depends="phoenix-xdoclet"> <mkdir dir="${build.lib}"/> @@ -242,14 +250,21 @@ </zipfileset> </jar> - <jar jarfile="${build.lib}/phoenix-engine.jar" - basedir="${build.classes}" > - - <include name="org/apache/avalon/phoenix/engine/**"/> - <include name="org/apache/avalon/phoenix/frontends/**"/> - <include name="org/apache/avalon/phoenix/components/**"/> - <include name="org/apache/avalon/phoenix/interfaces/**"/> - <exclude name="org/apache/avalon/phoenix/launcher/**"/> + <jar jarfile="${build.lib}/phoenix-engine.jar"> + <fileset dir="${build.classes}" > + <include name="org/apache/avalon/phoenix/engine/**"/> + <include name="org/apache/avalon/phoenix/frontends/**"/> + <include name="org/apache/avalon/phoenix/components/**"/> + <include name="org/apache/avalon/phoenix/interfaces/**"/> + <exclude name="org/apache/avalon/phoenix/launcher/**"/> + </fileset> + <fileset dir="${build.xdoclet}" > + <include name="org/apache/avalon/phoenix/engine/**"/> + <include name="org/apache/avalon/phoenix/frontends/**"/> + <include name="org/apache/avalon/phoenix/components/**"/> + <include name="org/apache/avalon/phoenix/interfaces/**"/> + <exclude name="org/apache/avalon/phoenix/launcher/**"/> + </fileset> </jar> <jar jarfile="${build.lib}/phoenix-bsh-commands.jar"> @@ -260,6 +275,7 @@ </target> + <target name="checkstyle" if="do.checkstyle" description="Checkstyle"> <!-- this invocation of checkstyle requires that checkstyle be downloaded and setup --> @@ -298,29 +314,6 @@ </checkstyle> </target> - <target name="checkstyle-report" - depends="checkstyle" - if="do.checkstyle" - description="Generate Checkstyle Report"> - - <mkdir dir="${build.reports}/checkstyle"/> - <property name="checkstyle.pathhack" location="."/> - <style style="${tools.dir}/etc/checkstyle-frames.xsl" in="${build.dir}/checkstyle-results.xml" - out="${build.reports}/checkstyle/delete-me.html"> - <param name="pathhack" expression="${checkstyle.pathhack}"/> - </style> - - </target> - - <!-- Create the lite build --> - <target name="dist-lite-jmx" depends="jars" if="jmx-ri.present"> - <property name="bin.dist.lib" value="${bin.dist.dir}/lib"/> - <mkdir dir="${bin.dist.lib}"/> - - <copy file="${jmxri.jar}" todir="${bin.dist.lib}"/> - <copy file="${jmxtools.jar}" todir="${bin.dist.lib}"/> - </target> - <!-- Copy BeanShell jars --> <target name="dist-beanshell" description="Copies Beanshell jars" if="beanshell.jars"> <copy file="${build.lib}/phoenix-bsh-commands.jar" todir="${bin.dist.lib}"/> @@ -332,7 +325,7 @@ </target> <!-- Create the lite build --> - <target name="dist-lite" depends="dist-lite-jmx" + <target name="dist-lite" depends="jars" description="generates the Phoenix distribution without the javadocs"> <property name="bin.dist.bin" value="${bin.dist.dir}/bin"/> 1.2 +26 -21 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/application/ExportHelper.java Index: ExportHelper.java =================================================================== RCS file: /home/cvs/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/application/ExportHelper.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ExportHelper.java 19 May 2002 02:31:04 -0000 1.1 +++ ExportHelper.java 30 Jul 2002 12:31:16 -0000 1.2 @@ -40,23 +40,37 @@ final String name = metaData.getName(); final ClassLoader classLoader = block.getClass().getClassLoader(); + final Class[] serviceClasses = new Class[ services.length ]; + for( int i = 0; i < services.length; i++ ) { final ServiceDescriptor service = services[ i ]; try { - final Class clazz = classLoader.loadClass( service.getName() ); - context.exportObject( name, clazz, block ); + serviceClasses[ i ] = classLoader.loadClass( service.getName() ); } catch( final Exception e ) { final String reason = e.toString(); final String message = - REZ.getString( "export.error", name, service.getName(), reason ); + REZ.getString( "bad-mx-service.error", name, service.getName(), reason ); getLogger().error( message ); throw new CascadingException( message, e ); } } + + try + { + context.exportObject( name, serviceClasses, block ); + } + catch( final Exception e ) + { + final String message = + REZ.getString( "export.error", name, e ); + getLogger().error( message ); + throw new CascadingException( message, e ); + } + } /** @@ -67,25 +81,16 @@ final BlockMetaData metaData, final Object block ) { - final ServiceDescriptor[] services = metaData.getBlockInfo().getManagementAccessPoints(); final String name = metaData.getName(); - final ClassLoader classLoader = block.getClass().getClassLoader(); - - for( int i = 0; i < services.length; i++ ) + try { - final ServiceDescriptor service = services[ i ]; - try - { - final Class clazz = classLoader.loadClass( service.getName() ); - context.unexportObject( name, clazz ); - } - catch( final Exception e ) - { - final String reason = e.toString(); - final String message = - REZ.getString( "unexport.error", name, service.getName(), reason ); - getLogger().error( message ); - } + context.unexportObject( name ); + } + catch( final Exception e ) + { + final String message = + REZ.getString( "unexport.error", name, e ); + getLogger().error( message ); } } } 1.25 +3 -2 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/application/Resources.properties Index: Resources.properties =================================================================== RCS file: /home/cvs/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/application/Resources.properties,v retrieving revision 1.24 retrieving revision 1.25 diff -u -r1.24 -r1.25 --- Resources.properties 13 Jul 2002 19:36:57 -0000 1.24 +++ Resources.properties 30 Jul 2002 12:31:16 -0000 1.25 @@ -12,8 +12,9 @@ lifecycle-fail.error=Block named "{0}" failed to pass through the {1,choice,0#Creation|1#Logger initialization|2#Contextualization|3#Composing|4#Configuration|5#Parameterizing|6#Initialization|7#Starting|8#Stopping|9#Disposing|10#Destruction} stage. (Reason: {2}). -export.error=Block named "{0}" failed to have the "{1}" management service exposed to management system. (Reason: {2}) -unexport.error=Block named "{0}" failed to have the "{1}" management service removed from management system. (Reason: {2}) +bad-mx-service.error=Block named "{0}" failed to have the "{1}" management service exposed to management system as class could not be loaded. +export.error=Unable to export Block named "{0}" to management system. +unexport.error=Unable to unexport Block named "{0}" from management system. helper.isa-blocklistener.error=Warning: Using deprecated BlockListener interface for listener named "{0}" with classname "{1}". 1.75 +4 -2 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/embeddor/DefaultEmbeddor.java Index: DefaultEmbeddor.java =================================================================== RCS file: /home/cvs/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/embeddor/DefaultEmbeddor.java,v retrieving revision 1.74 retrieving revision 1.75 diff -u -r1.74 -r1.75 --- DefaultEmbeddor.java 26 Jul 2002 09:49:21 -0000 1.74 +++ DefaultEmbeddor.java 30 Jul 2002 12:31:16 -0000 1.75 @@ -417,6 +417,7 @@ * until setupComponents() is called. */ private synchronized void createComponents() + throws Exception { try { @@ -428,11 +429,12 @@ m_entries[ i ].setObject( object ); } } - catch( Exception e ) + catch( final Exception e ) { final String message = REZ.getString( "embeddor.error.createComponents.failed" ); getLogger().fatalError( message, e ); + throw new Exception( message, e ); } } @@ -636,7 +638,7 @@ final SystemManager systemManager = (SystemManager)getServiceManager().lookup( SystemManager.ROLE ); - SystemManager componentManager = systemManager.getSubContext( null, "component" ); + final SystemManager componentManager = systemManager.getSubContext( null, "component" ); componentManager.unregister( ManagementRegistration.EMBEDDOR.getName() ); 1.25 +3 -3 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/kernel/DefaultApplicationContext.java Index: DefaultApplicationContext.java =================================================================== RCS file: /home/cvs/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/kernel/DefaultApplicationContext.java,v retrieving revision 1.24 retrieving revision 1.25 diff -u -r1.24 -r1.25 --- DefaultApplicationContext.java 26 Jul 2002 09:49:21 -0000 1.24 +++ DefaultApplicationContext.java 30 Jul 2002 12:31:16 -0000 1.25 @@ -136,11 +136,11 @@ * @param object the actual object to export */ public void exportObject( final String name, - final Class service, + final Class[] services, final Object object ) throws Exception { - m_blockManager.register( name, object, new Class[]{service} ); + m_blockManager.register( name, object, services ); } /** @@ -149,7 +149,7 @@ * @param name the name of object to unexport * @param service the interface of object with which to unexport */ - public void unexportObject( final String name, final Class service ) + public void unexportObject( final String name ) throws Exception { m_blockManager.unregister( name ); 1.3 +206 -67 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/manager/AbstractJMXManager.java Index: AbstractJMXManager.java =================================================================== RCS file: /home/cvs/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/manager/AbstractJMXManager.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- AbstractJMXManager.java 26 Jul 2002 09:49:21 -0000 1.2 +++ AbstractJMXManager.java 30 Jul 2002 12:31:16 -0000 1.3 @@ -7,15 +7,17 @@ */ package org.apache.avalon.phoenix.components.manager; +import java.lang.reflect.Constructor; +import java.util.Iterator; +import java.util.Set; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; +import javax.management.modelmbean.ModelMBean; +import javax.management.modelmbean.ModelMBeanInfo; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; -import org.apache.avalon.phoenix.components.kernel.DefaultKernel; -import org.apache.avalon.phoenix.components.kernel.DefaultKernelMBean; import org.apache.avalon.phoenix.interfaces.ManagerException; -import org.apache.excalibur.baxter.JavaBeanMBean; /** * An abstract class via which JMX Managers can extend. @@ -29,9 +31,8 @@ { private static final Resources REZ = ResourceManager.getPackageResources( AbstractJMXManager.class ); - + private MBeanInfoBuilder topicBuilder; private MBeanServer m_mBeanServer; - private String m_domain = "Phoenix"; public void initialize() @@ -41,6 +42,9 @@ final MBeanServer mBeanServer = createMBeanServer(); setMBeanServer( mBeanServer ); + + topicBuilder = new MBeanInfoBuilder(); + setupLogger( topicBuilder ); } public void start() @@ -76,10 +80,9 @@ { try { - final Object mBean = createMBean( object, interfaces ); - final ObjectName objectName = createObjectName( name ); - getMBeanServer().registerMBean( mBean, objectName ); - return mBean; + final Target target = createTarget( name, object, interfaces ); + exportTarget( target ); + return target; } catch( final Exception e ) { @@ -90,63 +93,6 @@ } /** - * Create MBean for specified object (and interfaces if any). - * - * @param object the object - * @param interfaces the interfaces to export - * @return the MBean - * @throws ManagerException if unable to create MBean - */ - private Object createMBean( final Object object, - final Class[] interfaces ) - throws ManagerException - { - if( null != interfaces ) - { - return new JavaBeanMBean( object, interfaces ); - } - else - { - return createMBean( object ); - } - } - - /** - * Create JMX name for object. - * - * @param name the name of object - * @return the {@link ObjectName} representing object - * @throws MalformedObjectNameException if malformed name - */ - private ObjectName createObjectName( final String name ) - throws MalformedObjectNameException - { - return new ObjectName( getDomain() + ":" + name ); - } - - /** - * Create a MBean for specified object. - * The following policy is used top create the MBean... - * - * @param object the object to create MBean for - * @return the MBean to be exported - * @throws ManagerException if an error occurs - */ - private Object createMBean( final Object object ) - throws ManagerException - { - //HACK: ugly Testing hack!! - if( object instanceof DefaultKernel ) - { - return new DefaultKernelMBean( (DefaultKernel)object ); - } - else - { - return new JavaBeanMBean( object ); - } - } - - /** * Stop the exported object from being managed. * * @param name the name of object @@ -210,4 +156,197 @@ */ protected abstract MBeanServer createMBeanServer() throws Exception; + + /** + * Creates a target that can then be exported for management. A topic is created + * for each interface and for topics specified in the mxinfo file, if present + * + * @param name name of the target + * @param object managed object + * @param interfaces interfaces to be exported + * @return the management target + */ + protected Target createTarget( final String name, + final Object object, + Class[] interfaces ) + { + final Target target = new Target( name, object ); + try + { + topicBuilder.build( target, object.getClass(), interfaces ); + } + catch( final Exception e ) + { + getLogger().debug( e.getMessage(), e ); + } + + return target; + } + + /** + * Exports the target to the management repository. This is done by exporting + * each topic in the target. + * + * @param target the management target + */ + protected void exportTarget( final Target target ) + throws Exception + { + // loop through each topic and export it + final Set topicNames = target.getTopicNames(); + final Iterator i = topicNames.iterator(); + while( i.hasNext() ) + { + final String topicName = (String)i.next(); + final ModelMBeanInfo topic = target.getTopic( topicName ); + final String targetName = target.getName(); + final Object managedResource = target.getManagedResource(); + Object targetObject = managedResource; + if( topic.getMBeanDescriptor().getFieldValue( "proxyClassName" ) != null ) + { + targetObject = createManagementProxy( topic, managedResource ); + } + + // use a proxy adapter class to manage object + exportTopic( topic, + targetObject, + targetName ); + } + } + + /** + * Exports the topic to the management repository. The name of the topic in the + * management repository will be the target name + the topic name + * + * @param topic the descriptor for the topic + * @param target to be managed + * @param targetName the target's name + */ + protected Object exportTopic( final ModelMBeanInfo topic, + final Object target, + final String targetName ) + throws Exception + { + final Object mBean = createMBean( topic, target ); + final ObjectName objectName = createObjectName( targetName + ",topic=" + topic.getDescription() ); + getMBeanServer().registerMBean( mBean, objectName ); + + // debugging stuff. + /* + ModelMBean modelMBean = (ModelMBean)mBean; + ModelMBeanInfo modelMBeanInfo = (ModelMBeanInfo)modelMBean.getMBeanInfo(); + MBeanAttributeInfo[] attList = modelMBeanInfo.getAttributes(); + for( int i = 0; i < attList.length; i++ ) + { + ModelMBeanAttributeInfo mbai = (ModelMBeanAttributeInfo)attList[ i ]; + Descriptor d = mbai.getDescriptor(); + String[] fieldNames = d.getFieldNames(); + for( int j = 0; j < fieldNames.length; j++ ) + { + String fieldName = fieldNames[ j ]; + System.out.println( "Field name = " + fieldName + + " / value = " + d.getFieldValue( fieldName ) + + "::" +mbai.getType() + " value " + + modelMBean.getAttribute( mbai.getName() ) + " for " + mbai.getName() ); + } + } + */ + + return mBean; + } + + /** + * Create a MBean for specified object. + * The following policy is used top create the MBean... + * + * @param target the object to create MBean for + * @return the MBean to be exported + * @throws ManagerException if an error occurs + */ + private Object createMBean( final ModelMBeanInfo topic, + final Object target ) + throws ManagerException + { + final String className = topic.getClassName(); + // Load the ModelMBean implementation class + Class clazz; + try + { + clazz = Class.forName( className ); + } + catch( Exception e ) + { + final String message = + REZ.getString( "jmxmanager.error.mbean.load.class", + className ); + getLogger().error( message, e ); + throw new ManagerException( message, e ); + } + + // Create a new ModelMBean instance + ModelMBean mbean = null; + try + { + mbean = (ModelMBean)clazz.newInstance(); + mbean.setModelMBeanInfo( topic ); + } + catch( final Exception e ) + { + final String message = + REZ.getString( "jmxmanager.error.mbean.instantiate", + className ); + getLogger().error( message, e ); + throw new ManagerException( message, e ); + } + + // Set the managed resource (if any) + try + { + if( null != target ) + { + mbean.setManagedResource( target, "ObjectReference" ); + } + } + catch( Exception e ) + { + final String message = + REZ.getString( "jmxmanager.error.mbean.set.resource", + className ); + getLogger().error( message, e ); + throw new ManagerException( message, e ); + } + + return mbean; + } + + /** + * Create JMX name for object. + * + * @param name the name of object + * @return the {@link ObjectName} representing object + * @throws MalformedObjectNameException if malformed name + */ + private ObjectName createObjectName( final String name ) + throws MalformedObjectNameException + { + return new ObjectName( getDomain() + ":" + name ); + } + + /** + * Instantiates a proxy management object for the target object + * + * this should move out of bridge and into Registry, it isn't specifically for jmx + */ + private Object createManagementProxy( final ModelMBeanInfo topic, + final Object managedObject ) + throws Exception + { + final String proxyClassname = (String)topic.getMBeanDescriptor().getFieldValue( "proxyClassName" ); + final ClassLoader classLoader = managedObject.getClass().getClassLoader(); + final Class proxyClass = classLoader.loadClass( proxyClassname ); + final Class[] argTypes = new Class[]{Object.class}; + final Object[] argValues = new Object[]{managedObject}; + final Constructor constructor = proxyClass.getConstructor( argTypes ); + return constructor.newInstance( argValues ); + } } 1.13 +2 -1 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/manager/MX4JSystemManager.java Index: MX4JSystemManager.java =================================================================== RCS file: /home/cvs/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/manager/MX4JSystemManager.java,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- MX4JSystemManager.java 26 Jul 2002 09:49:21 -0000 1.12 +++ MX4JSystemManager.java 30 Jul 2002 12:31:16 -0000 1.13 @@ -25,7 +25,8 @@ * @author <a href="mailto:[EMAIL PROTECTED]">Huw Roberts</a> */ public class MX4JSystemManager - extends AbstractJMXManager implements Configurable + extends AbstractJMXManager + implements Configurable { private static final int DEFAULT_HTTPADAPTER_PORT = Integer.getInteger( "phoenix.adapter.http", 8082 ).intValue(); 1.5 +16 -0 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/manager/Resources.properties Index: Resources.properties =================================================================== RCS file: /home/cvs/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/manager/Resources.properties,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- Resources.properties 5 Mar 2002 12:39:22 -0000 1.4 +++ Resources.properties 30 Jul 2002 12:31:16 -0000 1.5 @@ -1,4 +1,18 @@ manager.error.interfaces.null=Interfaces parameter is null for object {0}. +mxinfo.error.missing.method=Can't find method {0}. +mxinfo.error.missing.property=Can't find property named: {0}. +mxinfo.error.proxy=Failed to create proxy topic for {0}. +jmxmanager.error.mbean.set.resource=Failed to set managed resource on MBean of class {0}. +jmxmanager.error.mbean.instantiate=Failed to instantiate MBean of class {0}. +mxinfo.debug.building.proxy.topic=Building proxyTopic {0}. +mxinfo.error.topic=Failed to create topic for {0}. +mxinfo.debug.adding.topic=Adding topic {0}. +subcontext.error.no.subcontext=Cannot request a named subcontext here. +subcontext.error.type.null=type cannot be null or empty +mxinfo.error.introspect=Can't introspect class {0}. +mxinfo.error.target=Failed to create topics for target {0}. +mxinfo.debug.found.mxinfo=mxinfo found for {0}. +mxinfo.debug.building=Building target for {0}. manager.error.unregister.noentry=No entry with name {0}. manager.error.verify.notinterface=Can not export {0} for management as it is not an interface. manager.error.verify.notinstance=Can not export {0} for management as object does not implement interface. @@ -7,4 +21,6 @@ jmxmanager.error.export.fail=Unable to export {0} as mBean. jmxmanager.error.unexport.fail=Unable to unexport {0} as mBean. +jmxmanager.error.mbean.load.class=Failed to find MBean of class {0} in classpath. +mxinfo.error.file=Failed to read mxinfo file {0}. jmxmanager.error.mbeanserver.create=Failed to create MBean Server of class {0}. 1.4 +9 -5 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/manager/SubContext.java Index: SubContext.java =================================================================== RCS file: /home/cvs/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/manager/SubContext.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- SubContext.java 26 Jul 2002 09:49:21 -0000 1.3 +++ SubContext.java 30 Jul 2002 12:31:16 -0000 1.4 @@ -8,6 +8,8 @@ package org.apache.avalon.phoenix.components.manager; import java.util.HashMap; +import org.apache.avalon.excalibur.i18n.ResourceManager; +import org.apache.avalon.excalibur.i18n.Resources; import org.apache.avalon.phoenix.interfaces.ManagerException; import org.apache.avalon.phoenix.interfaces.SystemManager; @@ -21,14 +23,14 @@ class SubContext implements SystemManager { + private static final Resources REZ = + ResourceManager.getPackageResources( SubContext.class ); + private static final String EMPTY_STRING = ""; private final HashMap m_subcontexts = new HashMap(); - private final SystemManager m_parent; - private final String m_name; - private final String m_type; /** @@ -114,12 +116,14 @@ { if( null == type || EMPTY_STRING.equals( type ) ) { - final String message = "type cannot be null or empty"; + final String message = + REZ.getString( "subcontext.error.no.subcontext" ); throw new ManagerException( message ); } else if( null != name && this.m_type == null ) { - final String message = "cannot request a named subcontext here"; + final String message = + REZ.getString( "subcontext.error.no.subcontext" ); throw new ManagerException( message ); } 1.1 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/manager/MBeanInfoBuilder.java Index: MBeanInfoBuilder.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.avalon.phoenix.components.manager; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.MethodDescriptor; import java.beans.PropertyDescriptor; import java.io.InputStream; import java.lang.reflect.Method; import java.util.ArrayList; import javax.management.Descriptor; import javax.management.MBeanParameterInfo; import javax.management.modelmbean.ModelMBeanAttributeInfo; import javax.management.modelmbean.ModelMBeanConstructorInfo; import javax.management.modelmbean.ModelMBeanInfoSupport; import javax.management.modelmbean.ModelMBeanNotificationInfo; import javax.management.modelmbean.ModelMBeanOperationInfo; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.phoenix.tools.configuration.ConfigurationBuilder; import org.xml.sax.InputSource; /** * An MBeanInfoBuilder is responsible for building <code>ManagementTopic</code> * objects from Configuration objects. The format for Configuration object * is specified in the MxInfo specification. The information is loaded into * the Target structure. * * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a> * @author <a href="mailto:[EMAIL PROTECTED]">Huw Roberts</a> * @version $Revision: 1.1 $ $Date: 2002/07/30 12:31:16 $ */ public final class MBeanInfoBuilder extends AbstractLogEnabled { private static final Resources REZ = ResourceManager.getPackageResources( MBeanInfoBuilder.class ); private static final String REQ_MODEL_MBEAN = "javax.management.modelmbean.RequiredModelMBean"; public void build( final Target target, final Class managedClass, final Class[] interfaces ) throws ConfigurationException { final String notice = REZ.getString( "mxinfo.debug.building", managedClass.getName() ); getLogger().debug( notice ); // if the managed class has an mxinfo file, build the target from it // (this includes any proxies) Configuration config = loadMxInfo( managedClass ); if( null != config ) { final String message = REZ.getString( "mxinfo.debug.found.mxinfo", managedClass.getName() ); getLogger().debug( message ); buildFromMxInfo( target, managedClass, config ); } // for each interface, generate a topic from its mxinfo file // or through introspection for( int i = 0, j = interfaces.length; i < j; i++ ) { try { config = loadMxInfo( interfaces[ i ] ); if( config == null ) { buildFromIntrospection( target, interfaces[ i ] ); } else { buildFromMxInfo( target, managedClass, config ); } } catch( final Exception e ) { final String message = REZ.getString( "mxinfo.error.target", target.getName() ); getLogger().error( message, e ); throw new ConfigurationException( message ); } } } /** * Create a <code>ModelMBeanInfoSupport</code> object for specified classname from * specified configuration data. */ private void buildFromMxInfo( final Target target, final Class managedClass, final Configuration config ) throws ConfigurationException { BeanInfo beanInfo; try { beanInfo = Introspector.getBeanInfo( managedClass ); } catch( final Exception e ) { final String message = REZ.getString( "mxinfo.error.introspect", managedClass.getName() ); throw new ConfigurationException( message, e ); } // load each topic final Configuration[] topicsConfig = config.getChildren( "topic" ); for( int i = 0; i < topicsConfig.length; i++ ) { final ModelMBeanInfoSupport topic = buildTopic( topicsConfig[ i ], beanInfo ); target.addTopic( topic ); } // load each proxy final Configuration[] proxysConfig = config.getChildren( "proxy" ); for( int i = 0; i < proxysConfig.length; i++ ) { final ModelMBeanInfoSupport topic = buildProxyTopic( proxysConfig[ i ], managedClass ); target.addTopic( topic ); } } /** * Builds a topic based on introspection of the interface */ private void buildFromIntrospection( final Target target, final Class interfaceClass ) throws ConfigurationException { try { final BeanInfo beanInfo = Introspector.getBeanInfo( interfaceClass ); // do the methods final MethodDescriptor[] methods = beanInfo.getMethodDescriptors(); final ArrayList operations = new ArrayList(); for( int j = 0; j < methods.length; j++ ) { // skip getters and setters final String name = methods[ j ].getName(); if( !(name.startsWith( "get" ) || name.startsWith( "set" ) || name.startsWith( "is" )) ) { operations.add( buildOperationInfo( methods[ j ], null ) ); } } final ModelMBeanOperationInfo[] operationList = (ModelMBeanOperationInfo[]) operations.toArray( new ModelMBeanOperationInfo[ 0 ] ); // do the attributes final PropertyDescriptor[] propertys = beanInfo.getPropertyDescriptors(); final ModelMBeanAttributeInfo[] attributes = new ModelMBeanAttributeInfo[ propertys.length ]; for( int j = 0; j < propertys.length; j++ ) { attributes[ j ] = buildAttributeInfo( propertys[ j ], null ); } final ModelMBeanConstructorInfo[] constructors = new ModelMBeanConstructorInfo[ 0 ]; final ModelMBeanNotificationInfo[] notifications = new ModelMBeanNotificationInfo[ 0 ]; final String shortName = getShortName( interfaceClass.getName() ); final ModelMBeanInfoSupport topic = new ModelMBeanInfoSupport( REQ_MODEL_MBEAN, shortName, attributes, constructors, operationList, notifications ); // add it to target final String message = REZ.getString( "mxinfo.debug.adding.topic", topic.getDescription() ); getLogger().debug( message ); target.addTopic( topic ); } catch( final Exception e ) { final String message = REZ.getString( "mxinfo.error.topic", interfaceClass ); throw new ConfigurationException( message, e ); } } /** * A utility method to build a <code>ModelMBeanInfoSupport</code> * object from specified configuration and BeanInfo. * * @return the created ModelMBeanInfoSupport * @throws ConfigurationException if an error occurs */ private ModelMBeanInfoSupport buildTopic( final Configuration config, final BeanInfo beanInfo ) throws ConfigurationException { final ModelMBeanAttributeInfo[] attributes = buildAttributeInfos( config, beanInfo ); final ModelMBeanOperationInfo[] operations = buildOperationInfos( config, beanInfo ); final ModelMBeanConstructorInfo[] constructors = new ModelMBeanConstructorInfo[ 0 ]; final ModelMBeanNotificationInfo[] notifications = new ModelMBeanNotificationInfo[ 0 ]; final String name = config.getAttribute( "name" ); final ModelMBeanInfoSupport topic = new ModelMBeanInfoSupport( REQ_MODEL_MBEAN, name, attributes, constructors, operations, notifications ); return topic; } /** * Build a topic for a proxy management class * * @param proxyTagConfig * @param managedClass * @return */ private ModelMBeanInfoSupport buildProxyTopic( final Configuration proxyTagConfig, final Class managedClass ) throws ConfigurationException { try { final String proxyName = proxyTagConfig.getAttribute( "name" ); final String message = REZ.getString( "mxinfo.debug.building.proxy.topic", proxyName ); getLogger().debug( message ); final Class proxyClass = managedClass.getClassLoader().loadClass( proxyName ); final Configuration classConfig = loadMxInfo( proxyClass ); final Configuration topicConfig = classConfig.getChild( "topic" ); final BeanInfo info = Introspector.getBeanInfo( proxyClass ); final ModelMBeanInfoSupport topic = buildTopic( topicConfig, info ); final Descriptor mBeanDescriptor = topic.getMBeanDescriptor(); mBeanDescriptor.setField( "proxyClassName", proxyName ); topic.setMBeanDescriptor( mBeanDescriptor ); return topic; } catch( final Exception e ) { if( e instanceof ConfigurationException ) { throw (ConfigurationException)e; } else { final String message = REZ.getString( "mxinfo.error.proxy", managedClass.getName() ); throw new ConfigurationException( message ); } } } /** * Builds the management attributes from the configuration * * @param config topic's configuration element * @param info managed class' BeanInfo from introspector * @throws ConfigurationException */ private ModelMBeanAttributeInfo[] buildAttributeInfos( final Configuration config, final BeanInfo info ) throws ConfigurationException { final Configuration[] attributesConfig = config.getChildren( "attribute" ); final ModelMBeanAttributeInfo[] attributeList = new ModelMBeanAttributeInfo[ attributesConfig.length ]; final PropertyDescriptor[] propertys = info.getPropertyDescriptors(); for( int i = 0; i < attributesConfig.length; i++ ) { final Configuration attribute = attributesConfig[ i ]; final String name = attribute.getAttribute( "name" ); final PropertyDescriptor property = getPropertyDescriptor( name, propertys ); attributeList[ i ] = buildAttributeInfo( property, attribute ); } return attributeList; } /** * Builds a management config * * @param property from BeanInfo * @param config configuration element - can be null, in which case defaults are used */ private ModelMBeanAttributeInfo buildAttributeInfo( final PropertyDescriptor property, final Configuration config ) { final String name = property.getName(); final Method readMethod = property.getReadMethod(); final Method writeMethod = property.getWriteMethod(); final String type = property.getPropertyType().getName(); String description = property.getDisplayName(); boolean isReadable = (readMethod != null); boolean isWriteable = (writeMethod != null); if( config != null ) { // use config info, or BeanInfo if config info is missing description = config.getAttribute( "description", description ); // defaults to true if there is a read method, otherwise defaults to false isReadable = config.getAttributeAsBoolean( "isReadable", true ) && isReadable; // defaults to true if there is a write method, otherwise defaults to false isWriteable = config.getAttributeAsBoolean( "isWriteable", true ) && isWriteable; } final boolean isIs = (readMethod != null) && readMethod.getName().startsWith( "is" ); final ModelMBeanAttributeInfo info = new ModelMBeanAttributeInfo( name, type, description, isReadable, isWriteable, isIs ); // additional info needed for modelMbean to work final Descriptor descriptor = info.getDescriptor(); descriptor.setField( "currencyTimeLimit", new Integer( 1 ) ); if( isReadable ) { descriptor.setField( "getMethod", readMethod.getName() ); } if( isWriteable ) { descriptor.setField( "setMethod", writeMethod.getName() ); } info.setDescriptor( descriptor ); return info; } /** * Returns the PropertyDescriptor with the specified name from the array */ private PropertyDescriptor getPropertyDescriptor( final String name, final PropertyDescriptor[] propertys ) throws ConfigurationException { for( int i = 0; i < propertys.length; i++ ) { if( propertys[ i ].getName().equals( name ) ) { return propertys[ i ]; } } final String message = REZ.getString( "mxinfo.error.missing.property", name ); throw new ConfigurationException( message ); } /** * Builds the management operations * * @param config topic configuration element to build from * @param info BeanInfo for managed class from introspector * @throws ConfigurationException */ private ModelMBeanOperationInfo[] buildOperationInfos( final Configuration config, final BeanInfo info ) throws ConfigurationException { final Configuration[] operationsConfig = config.getChildren( "operation" ); final ModelMBeanOperationInfo[] operations = new ModelMBeanOperationInfo[ operationsConfig.length ]; final MethodDescriptor[] methodDescriptors = info.getMethodDescriptors(); for( int i = 0; i < operationsConfig.length; i++ ) { final Configuration operation = operationsConfig[ i ]; final String name = operation.getAttribute( "name" ); final MethodDescriptor method = getMethodDescriptor( name, methodDescriptors ); operations[ i ] = buildOperationInfo( method, operation ); } return operations; } /** * Builds an operation descriptor from a configuration node * * @param method method as returned from beanInfo * @param config configuration element, can be null * @throws ConfigurationException if the configiration has the wrong elements * @return the operation descriptor based on the configuration */ private ModelMBeanOperationInfo buildOperationInfo( final MethodDescriptor method, final Configuration config ) throws ConfigurationException { ModelMBeanOperationInfo info; if( config == null ) { info = new ModelMBeanOperationInfo( method.getDisplayName(), method.getMethod() ); } else { final String name = method.getName(); final String type = method.getMethod().getReturnType().getName(); final String description = config.getAttribute( "description", method.getDisplayName() ); final int impact = config.getAttributeAsInteger( "impact", ModelMBeanOperationInfo.UNKNOWN ); final Configuration[] paramConfig = config.getChildren( "param" ); final MBeanParameterInfo[] params = new MBeanParameterInfo[ paramConfig.length ]; for( int i = 0; i < paramConfig.length; i++ ) { params[ i ] = buildParameterInfo( paramConfig[ i ] ); } info = new ModelMBeanOperationInfo( name, description, params, type, impact ); } // additional info needed for modelMbean to work final Descriptor descriptor = info.getDescriptor(); descriptor.setField( "currencyTimeLimit", new Integer( 1 ) ); info.setDescriptor( descriptor ); return info; } /** * Returns the MethodDescriptor with the specified name from the array */ private MethodDescriptor getMethodDescriptor( final String name, final MethodDescriptor[] methods ) throws ConfigurationException { for( int i = 0; i < methods.length; i++ ) { if( methods[ i ].getName().equals( name ) ) { return methods[ i ]; } } final String message = REZ.getString( "mxinfo.error.missing.method", name ); throw new ConfigurationException( message ); } /** * Builds the param descriptor from the configuration data * * @throws ConfigurationException if configuration not structured corretly * @return the descriptor */ private MBeanParameterInfo buildParameterInfo( Configuration paramConfig ) throws ConfigurationException { final String name = paramConfig.getAttribute( "name" ); final String description = paramConfig.getAttribute( "description" ); final String type = paramConfig.getAttribute( "type" ); return new MBeanParameterInfo( name, type, description ); } /** * Returns the configuration for the class or null if there is no mxinfo * file for it. * * @param clazz the class to load the configuration for * @throws ConfigurationException * @return the configuration file, or null if none exists */ private Configuration loadMxInfo( final Class clazz ) throws ConfigurationException { final String mxinfoName = "/" + clazz.getName().replace( '.', '/' ) + ".mxinfo"; try { InputStream stream = clazz.getResourceAsStream( mxinfoName ); if( null == stream ) { return null; } final InputSource source = new InputSource( stream ); // build with validation against DTD return ConfigurationBuilder.build( source, true ); } catch( Exception e ) { final String message = REZ.getString( "mxinfo.error.file", mxinfoName ); getLogger().error( message, e ); throw new ConfigurationException( message ); } } /** * Returns the class name without the package name */ private String getShortName( final String className ) { return className.substring( className.lastIndexOf( '.' ) + 1 ); } } 1.1 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/manager/Target.java Index: Target.java =================================================================== /* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.avalon.phoenix.components.manager; import java.util.HashMap; import java.util.Set; import javax.management.modelmbean.ModelMBeanInfo; /** * It reprensents a managed object in the managegement space. It is a container for * zero or more management topics and zero or more management lists. * * @author robertsh * @version $$ */ public class Target { private final String m_name; private final HashMap m_topics; private final Object m_managedResource; /** * Creates new Target * * @param name the name for the target * @param managedResource the object that this managedResource represents in the management hierarchy */ public Target( final String name, final Object managedResource ) { m_name = name; m_managedResource = managedResource; m_topics = new HashMap(); } /** * Returns the name of the Target * @return the name */ public String getName() { return m_name; } /** * Returns the object managed by the target * * @return the managed object */ public Object getManagedResource() { return m_managedResource; } /** * Topics are a set of attributes and operations relevant to a particular * aspect of an object. A Target must typically have at least one topic in * order to be manageable. * * @param topic */ public void addTopic( final ModelMBeanInfo topic ) { m_topics.put( topic.getDescription(), topic ); } /** * Removes a topic for this target * @param name the name of the topic to remove */ public void removeTopic( final String name ) { m_topics.remove( name ); } /** * Gets a topic for this Target * * @param name the name of the topic * @return the topic of that name */ public ModelMBeanInfo getTopic( final String name ) { return (ModelMBeanInfo)m_topics.get( name ); } /** * Returns the Set of topics for this Target * * @return the <CODE>Set</CODE> of topic names */ public Set getTopicNames() { return m_topics.keySet(); } } 1.14 +3 -4 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/interfaces/ApplicationContext.java Index: ApplicationContext.java =================================================================== RCS file: /home/cvs/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/interfaces/ApplicationContext.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- ApplicationContext.java 14 Jul 2002 02:27:16 -0000 1.13 +++ ApplicationContext.java 30 Jul 2002 12:31:17 -0000 1.14 @@ -32,19 +32,18 @@ * and using the specified name. * * @param name the name of object to export - * @param interfaceClass the interface of object with which to export + * @param interfaceClasses the interface of object with which to export * @param object the actual object to export */ - void exportObject( String name, Class interfaceClass, Object object ) + void exportObject( String name, Class[] interfaceClasses, Object object ) throws Exception; /** * Unexport specified object from management system. * * @param name the name of object to unexport - * @param interfaceClass the interface of object with which to unexport */ - void unexportObject( String name, Class interfaceClass ) + void unexportObject( String name ) throws Exception; /** 1.9 +1 -0 jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/interfaces/SystemManager.java Index: SystemManager.java =================================================================== RCS file: /home/cvs/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/interfaces/SystemManager.java,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- SystemManager.java 13 Jul 2002 10:15:13 -0000 1.8 +++ SystemManager.java 30 Jul 2002 12:31:17 -0000 1.9 @@ -63,6 +63,7 @@ * is created. * * @param name name of the object in the parent context that will own this one + * @param type of objects that will be managed in this context * @throws ManagerException if context cannot be created or retrieved * @return the subcontext with the specified name */
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>