JBoss 4.0 - The Official Guide

JBoss includes adaptors that allow access to the JMX MBeanServer from outside the JBoss server VM. The current adaptors include HTML, an RMI interface, and an EJB.

Inspecting the Server: The JMX Console Web Application

JBoss comes with its own implementation of a JMX HTML adaptor that allows you to view the server's MBeans, using a standard web browser. The default URL for the console web application is http://localhost:8080/jmx-console/. If you browse to this location, you will see something similar to what is presented in Figure 2.12.

Figure 2.12. The JBoss JMX Console web application agent view.

The top view is called the agent view, and it provides a listing of all MBeans registered with the MBeanServer, sorted by the domain portion of the MBean's ObjectName. Under each domain you can see the MBeans that are in that domain. When you select one of the MBeans, you are taken to the MBean view, where you can view and edit an MBean's attributes as well as invoke operations. As an example, Figure 2.13 shows the MBean view for the jboss.system:type=Server MBean.

Figure 2.13. The MBean view for the jboss.system:type=Server MBean.

The source code for the JMX Console web application is located in the varia module, under the src/ main/org/jboss/jmx directory. Its web pages are located under varia/src/resources/jmx. The application is a simple MVC servlet with JSP views that utilize the MBeanServer.

Securing the JMX Console

Because the JMX Console web application is just a standard servlet, it can be secured using standard J2EE role-based security. The jmx-console.war is deployed as an unpacked WAR that includes template settings for quickly enabling simple username- and password-based access restrictions. If you look at the jmx-console.war in the server/default/deploy directory, you will find the web.xml and jboss-web.xml descriptors in the WEB-INF directory and jmx-console-roles.properties and jmx-console-users.properties files under WEB-INF/classes.

By uncommenting the security sections of the web.xml and jboss-web.xml descriptors, as shown in Listing 2.10 and Listing 2.11, you enable HTTP basic authentication that restricts access to the JMX Console application to the user admin with password admin. The username and password are determined by the admin=admin line in the jmx-console-users.properties file.

Listing 2.10. The jmx-console.war web.xml Descriptors, with the Security Elements Uncommented

<?xml version="1.0"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <!-- ... --> <!-- A security constraint that restricts access to the HTML JMX console to users with the role JBossAdmin. Edit the roles to what you want and uncomment the WEB-INF/jboss-web.xml/security-domain element to enable secured access to the HTML JMX console. --> <security-constraint> <web-resource-collection> <web-resource-name>HtmlAdaptor</web-resource-name> <description> An example security config that only allows users with the role JBossAdmin to access the HTML JMX console web application </description> <url-pattern>/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>JBossAdmin</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>JBoss JMX Console</realm-name> </login-config> <security-role> <role-name>JBossAdmin</role-name> </security-role> </web-app>

Listing 2.11. The jmx-console.war jboss-web.xml Descriptors, with the Security Elements Uncommented

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.3//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_3_0.dtd"> <jboss-web> <!-- Uncomment the security-domain to enable security. You will need to edit the htmladaptor login configuration to set up the login modules used to authenticate users. --> <security-domain>java:/jaas/jmx-console</security-domain> </jboss-web>

Make these changes to uncomment the security code, and then when you try to access the JMX Console URL, you will see a dialog similar to the one shown in Figure 2.14.

Figure 2.14. The JMX Console basic HTTP login dialog.

By default JBoss uses properties files for securing access to the JMX Console application. To see how to better configure the security settings of web applications, see Chapter 8, "Security on JBoss."

Connecting to JMX Using RMI

JBoss supplies an RMI interface for connecting to the JMX MBeanServer. This interface is org.jboss.jmx.adaptor.rmi.RMIAdaptor. The RMIAdaptor interface is bound into JNDI in the default location jmx/invoker/RMIAdaptor, as well as jmx/rmi/RMIAdaptor for backward compatibility with older clients.

Listing 2.12 shows a client that makes use of the RMIAdaptor interface to query the MBeanInfo for the JNDIView MBean. It also invokes the MBean's list(boolean) method and displays the result.

Listing 2.12. A JMX Client That Uses the RMIAdaptor Interface

public class JMXBrowser { /** * @param args the command line arguments */ public static void main(String[] args) throws Exception { InitialContext ic = new InitialContext(); RMIAdaptor server = (RMIAdaptor) ic.lookup("jmx/invoker/RMIAdaptor"); // Get the MBeanInfo for the JNDIView MBean ObjectName name = new ObjectName("jboss:service=JNDIView"); MBeanInfo info = server.getMBeanInfo(name); System.out.println("JNDIView Class: " + info.getClassName()); MBeanOperationInfo[] opInfo = info.getOperations(); System.out.println("JNDIView Operations: "); for(int o = 0; o < opInfo.length; o ++) { MBeanOperationInfo op = opInfo[o]; String returnType = op.getReturnType(); String opName = op.getName(); System.out.print(" + " + returnType + " " + opName + "("); MBeanParameterInfo[] params = op.getSignature(); for(int p = 0; p < params.length; p++) { MBeanParameterInfo paramInfo = params[p]; String pname = paramInfo.getName(); String type = paramInfo.getType(); if (pname.equals(type)) { System.out.print(type); } else { System.out.print(type + " " + name); } if (p < params.length-1) { System.out.print(','); } } System.out.println(")"); } // Invoke the list(boolean) op String[] sig = {"boolean"}; Object[] opArgs = {Boolean.TRUE}; Object result = server.invoke(name, "list", opArgs, sig); System.out.println("JNDIView.list(true) output:\n"+result); } }

To test the client access using the RMIAdaptor, you should run the following:

[View full width]

[examples]$ ant -Dchap=chap2 -Dex=4 run-example ... run-example4: [java] JNDIView Class: org.jboss.mx.modelmbean.XMBean [java] JNDIView Operations: [java] + java.lang.String list(boolean jboss:service=JNDIView) [java] + java.lang.String listXML() [java] + void create() [java] + void start() [java] + void stop() [java] + void destroy() [java] + void jbossInternalLifecycle(java.lang.String jboss:service=JNDIView) [java] + java.lang.String getName() [java] + int getState() [java] + java.lang.String getStateString() [java] JNDIView.list(true) output: [java] <h1>java: Namespace</h1> [java] <pre> [java] +- XAConnectionFactory (class: org.jboss.mq.SpyXAConnectionFactory) [java] +- DefaultDS (class: javax.sql.DataSource) [java] +- SecurityProxyFactory (class: org.jboss.security.SubjectSecurityProxyFactory) [java] +- DefaultJMSProvider (class: org.jboss.jms.jndi.JNDIProviderAdapter) [java] +- comp (class: javax.naming.Context) [java] +- JmsXA (class: org.jboss.resource.adapter.jms.JmsConnectionFactoryImpl) [java] +- ConnectionFactory (class: org.jboss.mq.SpyConnectionFactory) [java] +- jaas (class: javax.naming.Context) [java] | +- JmsXARealm (class: org.jboss.security.plugins.SecurityDomainContext) [java] | +- jbossmq (class: org.jboss.security.plugins.SecurityDomainContext) [java] | +- HsqlDbRealm (class: org.jboss.security.plugins.SecurityDomainContext) [java] +- timedCacheFactory (class: javax.naming.Context) [java] Failed to lookup: timedCacheFactory, errmsg=null [java] +- TransactionPropagationContextExporter (class: org.jboss.tm .TransactionPropagationContextFactory) [java] +- StdJMSPool (class: org.jboss.jms.asf.StdServerSessionPoolFactory) [java] +- Mail (class: javax.mail.Session) [java] +- TransactionPropagationContextImporter (class: org.jboss.tm .TransactionPropagationContextImporter) [java] +- TransactionManager (class: org.jboss.tm.TxManager) [java] </pre> [java] <h1>Global JNDI Namespace</h1> [java] <pre> [java] +- XAConnectionFactory (class: org.jboss.mq.SpyXAConnectionFactory) [java] +- UIL2ConnectionFactory[link -> ConnectionFactory] (class: javax.naming .LinkRef) [java] +- UserTransactionSessionFactory (proxy: $Proxy11 implements interface org .jboss.tm.usertx.interfaces.UserTransactionSessionFactory) [java] +- HTTPConnectionFactory (class: org.jboss.mq.SpyConnectionFactory) [java] +- console (class: org.jnp.interfaces.NamingContext) [java] | +- PluginManager (proxy: $Proxy36 implements interface org.jboss.console .manager.PluginManagerMBean) [java] +- UIL2XAConnectionFactory[link -> XAConnectionFactory] (class: javax.naming .LinkRef) [java] +- UUIDKeyGeneratorFactory (class: org.jboss.ejb.plugins.keygenerator.uuid .UUIDKeyGeneratorFactory) [java] +- HTTPXAConnectionFactory (class: org.j boss.mq.SpyXAConnectionFactory) [java] +- topic (class: org.jnp.interfaces.NamingContext) [java] | +- testDurableTopic (class: org.jboss.mq.SpyTopic) [java] | +- testTopic (class: org.jboss.mq.SpyTopic) [java] | +- securedTopic (class: org.jboss.mq.SpyTopic) [java] +- queue (class: org.jnp.interfaces.NamingContext) [java] | +- A (class: org.jboss.mq.SpyQueue) [java] | +- testQueue (class: org.jboss.mq.SpyQueue) [java] | +- ex (class: org.jboss.mq.SpyQueue) [java] | +- DLQ (class: org.jboss.mq.SpyQueue) [java] | +- D (class: org.jboss.mq.SpyQueue) [java] | +- C (class: org.jboss.mq.SpyQueue) [java] | +- B (class: org.jboss.mq.SpyQueue) [java] +- ConnectionFactory (class: org.jboss.mq.SpyConnectionFactory) [java] +- UserTransaction (class: org.jboss.tm.usertx.client.ClientUserTransaction) [java] +- jmx (class: org.jnp.interfaces.NamingContext) [java] | +- invoker (class: org.jnp.interfaces.NamingContext) [java] | | +- RMIAdaptor (proxy: $Proxy35 implements interface org.jboss.jmx .adaptor.rmi.RMIAdaptor, interface org.jboss.jmx.adaptor.rmi.RMIAdaptorExt) [java] | +- rmi (class: org.jnp.interfaces.NamingContext) [java] | | +- RMIAdaptor[link -> jmx/invoker/RMIAdaptor] (class: javax.naming .LinkRef) [java] +- HiLoKeyGeneratorFactory (class: org.jboss.ejb.plugins.keygenerator.hilo .HiLoKeyGeneratorFactory) [java] +- UILXAConnectionFactory[link -> XAConnectionFactory] (class: javax.naming .LinkRef) [java] +- UILConnectionFactory[link -> ConnectionFactory] (class: javax.naming.LinkRef) [java] </pre>

Command-Line Access to JMX

JBoss provides a simple command-line tool that allows for interaction with a remote JMX server instance. This tool is called Twiddle (for twiddling bits via JMX) and is located in the bin directory of the distribution. Twiddle is a command execution tool, not a general command shell. It is run using either the twiddle.sh script or the twiddle.bat script; and passing in a -h(--help) argument provides the basic syntax, and --help-commands shows what you can do with the tool:

[bin]$ ./twiddle.sh -h A JMX client to 'twiddle' with a remote JBoss server. usage: twiddle.sh [options] <command> [command_arguments] options: -h, --help Show this help message --help-commands Show a list of commands -H=<command> Show command specific help -c=command.properties Specify the command.properties file to use -D<name>[=<value>] Set a system property -- Stop processing options -s, --server=<url> The JNDI URL of the remote server -a, --adapter=<name> The JNDI name of the RMI adapter to use -q, --quiet Be somewhat more quiet

Connecting Twiddle to a Remote Server

By default the twiddle command connects to the local host at port 1099 to look up the default jmx/rmi/RMIAdaptor binding of the RMIAdaptor service as the connector for communicating with the JMX server. To connect to a different server/port combination, you can use the -s (--server) option:

[bin]$ ./twiddle.sh -s toki serverinfo -d jboss [bin]$ ./twiddle.sh -s toki:1099 serverinfo -d jboss

To connect using a different RMIAdaptor binding, you use the -a (--adapter) option:

[bin]$ ./twiddle.sh -s toki -a jmx/rmi/RMIAdaptor serverinfo -d jboss

Sample Twiddle Command Usage

To access basic information about a server, you use the serverinfo command:

[bin]$ ./twiddle.sh -H serverinfo Get information about the MBean server usage: serverinfo [options] options: -d, --domain Get the default domain -c, --count Get the MBean count -l, --list List the MBeans -- Stop processing options [bin]$ ./twiddle.sh --server=toki serverinfo --count 460 [bin]$ ./twiddle.sh --server=toki serverinfo --domain jboss

To query the server for the name of MBeans matching a pattern, you use the query command:

[bin]$ ./twiddle.sh -H query Query the server for a list of matching MBeans usage: query [options] <query> options: -c, --count Display the matching MBean count -- Stop processing options Examples: query all mbeans: query '*:*' query all mbeans in the jboss.j2ee domain: query 'jboss.j2ee:*' [bin]$ ./twiddle.sh -s toki query 'jboss:service=invoker,*' jboss:readonly=true,service=invoker,target=Naming,type=http jboss:service=invoker,type=jrmp jboss:service=invoker,type=local jboss:service=invoker,type=pooled jboss:service=invoker,type=http jboss:service=invoker,target=Naming,type=http

To get the attributes of an MBean, you use the get command:

[bin]$ ./twiddle.sh -H get Get the values of one or more MBean attributes usage: get [options] <name> [<attr>+] If no attribute names are given all readable attributes are retrieved options: --noprefix Do not display attribute name prefixes -- Stop processing options [bin]$ ./twiddle.sh get jboss:service=invoker,type=jrmp RMIObjectPort StateString RMIObjectPort=4444 StateString=Started [bin]$ ./twiddle.sh get jboss:service=invoker,type=jrmp ServerAddress=0.0.0.0 RMIClientSocketFactoryBean=null StateString=Started State=3 RMIServerSocketFactoryBean=org.jboss.net.sockets.DefaultSocketFactory@ad093076 EnableClassCaching=false SecurityDomain=null RMIServerSocketFactory=null Backlog=200 RMIObjectPort=4444 Name=JRMPInvoker RMIClientSocketFactory=null

To query the MBeanInfo for an MBean, you use the info command:

[bin]$ ./twiddle.sh -H info Get the metadata for an MBean usage: info <mbean-name> Use '*' to query for all attributes [bin]$ Description: Management Bean. +++ Attributes: Name: ServerAddress Type: java.lang.String Access: rw Name: RMIClientSocketFactoryBean Type: java.rmi.server.RMIClientSocketFactory Access: rw Name: StateString Type: java.lang.String Access: r- Name: State Type: int Access: r- Name: RMIServerSocketFactoryBean Type: java.rmi.server.RMIServerSocketFactory Access: rw Name: EnableClassCaching Type: boolean Access: rw Name: SecurityDomain Type: java.lang.String Access: rw Name: RMIServerSocketFactory Type: java.lang.String Access: rw Name: Backlog Type: int Access: rw Name: RMIObjectPort Type: int Access: rw Name: Name Type: java.lang.String Access: r- Name: RMIClientSocketFactory Type: java.lang.String Access: rw +++ Operations: void start() void jbossInternalLifecycle(java.lang.String java.lang.String) void create() void stop() void destroy()

To invoke an operation on an MBean, you use the invoker command:

[View full width]

[bin]$ ./twiddle.sh -H invoke Invoke an operation on an MBean usage: invoke [options] <query> <operation> (<arg>)* options: -q, --query-type[=<type>] Treat object name as a query -- Stop processing options query type: f[irst] Only invoke on the first matching name [default] a[ll] Invoke on all matching names [bin]$ ./twiddle.sh invoke jboss:service=JNDIView list true <h1>java: Namespace</h1> <pre> +- XAConnectionFactory (class: org.jboss.mq.SpyXAConnectionFactory) +- DefaultDS (class: javax.sql.DataSource) +- SecurityProxyFactory (class: org.jboss.security.SubjectSecurityProxyFactory) +- DefaultJMSProvider (class: org.jboss.jms.jndi.JNDIProviderAdapter) +- comp (class: javax.naming.Context) +- JmsXA (class: org.jboss.resource.adapter.jms.JmsConnectionFactoryImpl) +- ConnectionFactory (class: org.jboss.mq.SpyConnectionFactory) +- jaas (class: javax.naming.Context) | +- JmsXARealm (class: org.jboss.security.plugins.SecurityDomainContext) | +- jbossmq (class: org.jboss.security.plugins.SecurityDomainContext) | +- HsqlDbRealm (class: org.jboss.security.plugins.SecurityDomainContext) +- timedCacheFactory (class: javax.naming.Context) Failed to lookup: timedCacheFactory, errmsg=null +- TransactionPropagationContextExporter (class: org.jboss.tm .TransactionPropagationContextFactory) +- StdJMSPool (class: org.jboss.jms.asf.StdServerSessionPoolFactory) +- Mail (class: javax.mail.Session) +- TransactionPropagationContextImporter (class: org.jboss.tm .TransactionPropagationContextImporter) +- TransactionManager (class: org.jboss.tm.TxManager) </pre> <h1>Global JNDI Namespace</h1> <pre> +- XAConnectionFactory (class: org.jboss.mq.SpyXAConnectionFactory) +- UIL2ConnectionFactory[link -> ConnectionFactory] (class: javax.naming.LinkRef) +- UserTransactionSessionFactory (proxy: $Proxy11 implements interface org.jboss.tm .usertx.interfaces.UserTransactionSessionFactory) +- HTTPConnectionFactory (class: org.jboss.mq.SpyConnectionFactory) +- console (class: org.jnp.interfaces.NamingContext) | +- PluginManager (proxy: $Proxy36 implements interface org.jboss.console.manager .PluginManagerMBean) +- UIL2XAConnectionFactory[link -> XAConnectionFactory] (class: javax.naming.LinkRef) +- UUIDKeyGeneratorFactory (class: org.jboss.ejb.plugins.keygenerator.uuid .UUIDKeyGeneratorFactory) +- HTTPXAConnectionFactory (class: org.jboss.mq.SpyXAConnectionFactory) +- topic (class: org.jnp.interfaces.NamingContext) | +- testDurableTopic (class: org.jboss.mq.SpyTopic) | +- testTopic (class: org.jboss.mq.SpyTopic) | +- securedTopic (class: org.jboss.mq.SpyTopic) +- queue (class: org.jnp.interfaces.NamingContext) | +- A (class: org.jboss.mq.SpyQueue) | +- testQueue (class: org.jboss.mq.SpyQueue) | +- ex (class: org.jboss.mq.SpyQueue) | +- DLQ (class: org.jboss.mq.SpyQueue) | +- D (class: org.jboss.mq.SpyQueue) | +- C (class: org.jboss.mq.SpyQueue) | +- B (class: org.jboss.mq.SpyQueue) +- ConnectionFactory (class: org.jboss.mq.SpyConnectionFactory) +- UserTransaction (class: org.jboss.tm.usertx.client.ClientUserTransaction) +- jmx (class: org.jnp.interfaces.NamingContext) | +- invoker (class: org.jnp.interfaces.NamingContext) | | +- RMIAdaptor (proxy: $Proxy35 implements interface org.jboss.jmx.adaptor.rmi .RMIAdaptor, interface org.jboss.jmx.adaptor.rmi.RMIAdaptorExt) | +- rmi (class: org.jnp.interfaces.NamingContext) | | +- RMIAdaptor[link -> jmx/invoker/RMIAdaptor] (class: javax.naming.LinkRef) +- HiLoKeyGeneratorFactory (class: org.jboss.ejb.plugins.keygenerator.hilo .HiLoKeyGeneratorFactory) +- UILXAConnectionFactory[link -> XAConnectionFactory] (class: javax.naming.LinkRef) +- UILConnectionFactory[link -> ConnectionFactory] (class: javax.naming.LinkRef) </pre>

Connecting to JMX Using Any Protocol

With the detached invokers and a somewhat generalized proxy factory capability, you can really talk to the JMX server by using the InvokerAdaptorService and a proxy factory service to expose an RMIAdaptor or similar interface over your protocol of choice. You'll learn about the detached invoker notion, along with proxy factories, later in this chapter, in the section "Remote Access to Services, Detached Invokers." See the section "A Detached Invoker Example, the MBeanServer Invoker Adaptor Service," later in this chapter, for an example of an invoker service that allows you to access the MBean server by using to the RMIAdaptor interface over any protocol for which a proxy factory service exists.

Категории