# XML Configuration Loader

## Loading and starting MBeans using XML files

The `javax.management.loading.MLet` class provides a way to load and instantiate MBeans from a configuration file called MLet file. The MLet file has however a limited syntax, since it can only instantiate and register MBeans into an MBeanServer: no method invocation is possible, no MBean's unregistration, no possibility to use factories to create objects and so on. Furthermore, the MLet file format is not XML.

MX4J's `mx4j.tools.config.ConfigurationLoader` defines an XML configuration file format where it is possible to specify creation of objects, their registration into an MBeanServer, their unregistration, the invocation of methods, both via MBeanServer (JMX invocations) and via normal Java invocation.

Let's see a simple example that registers MX4J's HTTP adaptor into an MBeanServer. First, we need a small class that creates the MBeanServer and the ConfigurationLoader:

### Main class for configuration loading

    public class Startup
    {
       public static void main(final String[] args) throws Exception
       {
          // MX4J's logging redirection to Apache's Commons Logging
    //    mx4j.log.Log.redirectTo(new CommonsLogger());

          // Create the MBeanServer
          MBeanServer server = MBeanServerFactory.createMBeanServer();

          // Create the ConfigurationLoader
          ConfigurationLoader loader = new ConfigurationLoader();

          // Register the configuration loader into the MBeanServer
          ObjectName name = ObjectName.getInstance(":service=configuration");
          server.registerMBean(loader, name);

          // Tell the configuration loader the XML configuration file
          Reader reader = new BufferedReader(new FileReader(args[0]));
          loader.startup(reader);
          reader.close();
       }
    }

The class simply creates an MBeanServer, creates the ConfigurationLoader and tells the configuration loader to read an XML file from the path passed as argument. The XML file can be the following:

### XML file for configuration of MX4J's HttpAdaptor

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <configuration>
       <startup>
          <create classname="mx4j.tools.adaptor.http.HttpAdaptor" objectname="connectors:type=http" loadername="null">
             <arg type="int">9090</arg>
             <arg type="string">localhost</arg>
          </create>
          <create classname="mx4j.tools.adaptor.http.XSLTProcessor" objectname="connectors:type=http,processor=xslt" loadername="null"/>
          <call objectname="connectors:type=http" attribute="ProcessorNameString">
             <arg type="string">connectors:type=http,processor=xslt</arg>
          </call>
          <call objectname="connectors:type=http" operation="start"/>
       </startup>

       <shutdown>
          <call objectname="connectors:type=http" operation="stop"/>
       </shutdown>
    </configuration>

The first thing to notice is that the configuration file is splitted in 2 sections, namely startup and shutdown. We will see later how the shutdown section comes into play.

Let's examine the startup section. It contains the creation of the `mx4j.tools.adaptor.http.HttpAdaptor` MBean (passing 2 arguments to its constructor) and of the `mx4j.tools.adaptor.http.XSLTProcessor` MBean via the create element. These MBeans are registered in the MBeanServer that also manages the ConfigurationLoader MBean. Both these 2 operations are possible also with the MLet file. What is different is the possibility to set JMX attributes and invoke JMX operations on the MBeans just registered. This is achieved with the call element: first the XSLT processor is set onto the HTTP adaptor, then the HTTP adaptor itself is started.

Let's see now a more complex example: how to register and start a JSR 160 connector server.

### XML file for configuration of a JSR 160 connector server

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <configuration>
       <startup>
          <create classname="mx4j.tools.naming.NamingService" objectname="naming:type=rmiregistry">
             <arg type="int">1099</arg>
          </create>
          <call operation="start" objectname="naming:type=rmiregistry" />

          <object objectid="rmi">
             <call classname="javax.management.remote.JMXConnectorServerFactory" method="newJMXConnectorServer">
                <arg type="javax.management.remote.JMXServiceURL">
                   <new classname="javax.management.remote.JMXServiceURL">
                      <arg type="string">service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmx</arg>
                   </new>
                </arg>
                <arg type="java.util.Map" />
                <arg type="javax.management.MBeanServer" />
             </call>
          </object>
          <register objectname="connectors:type=rmi,protocol=jrmp">
             <arg type="object" refobjectid="rmi" />
          </register>
          <call method="start" refobjectid="rmi" />
       </startup>

       <shutdown>
          <call method="stop" refobjectid="rmi" />
          <call operation="stop" objectname="naming:type=rmiregistry" />
          <unregister objectname="connectors:type=rmi,protocol=jrmp" />
          <unregister objectname="naming:type=rmiregistry" />
       </shutdown>
    </configuration>

Note the usage of the object element. It is possible to assign an ID (in the example is "rmi") to objects that gets created in the XML file, and refer to them afterwards using the refobjectid attribute. Note also the syntax to invoke the static call to the `JMXConnectorServerFactory`, and the syntax to invoke non-JMX operations when calling "start" on the "rmi" object. Objects can be created by using the new element, and constructor arguments specified with the arg element. Note how null arguments are passed to the `JMXConnectorServerFactory` (the second and third argument of type Map and MBeanServer).

Let's now explain the meaning of the shutdown section. If the startup section defines how the MBeans should be created, registered and put into operation (for example by calling "start" operations on them), the shutdown section defines how the MBeans should be stopped from operating and eventually unregistered.

It remains the problem of how to make the configuration loader invoke the shutdown section.

This is done by specifying a port as attribute of the configuration element; the configuration loader will start a server socket on that port, so that from another JVM will be possible to connect to that socket and invoke the shutdown command. For security reasons, the server socket will listen on the loopback interface of the host, so that only JVMs started on the same host can invoke the shutdown section.

Below, an example of a class that invokes the shutdown section and a sample XML file that specifies the port for the server socket.

### Simple XML file that specifies the command port

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <configuration port="9876">
       <startup>
          <create classname="mx4j.tools.naming.NamingService" objectname="naming:type=rmiregistry">
             <arg type="int">1099</arg>
          </create>
          <call operation="start" objectname="naming:type=rmiregistry" />
       </startup>

       <shutdown>
          <call operation="stop" objectname="naming:type=rmiregistry" />
          <unregister objectname="naming:type=rmiregistry" />
       </shutdown>
    </configuration>

### Simple Java class that invokes "shutdown" to execute the shutdown section

    public class Shutdown
    {
       public static void main(String[] args) throws Exception
       {
          Socket socket = new Socket("127.0.0.1", 9876);
          socket.getOutputStream().write("shutdown".getBytes());
          socket.close();
       }
    }

The XML configuration DTD is the following:

### XML configuration DTD

    <!ELEMENT configuration (startup?, shutdown?)>
    <!ATTLIST configuration port CDATA #IMPLIED>

    <!ELEMENT startup (call*, create*, object*, register*)>

    <!ELEMENT shutdown (call*, unregister*)>

    <!ELEMENT call (arg*)>
    <!ATTLIST call classname CDATA #IMPLIED>
    <!ATTLIST call objectname CDATA #IMPLIED>
    <!ATTLIST call refobjectid CDATA #IMPLIED>
    <!ATTLIST call method CDATA #IMPLIED>
    <!ATTLIST call operation CDATA #IMPLIED>
    <!ATTLIST call attribute CDATA #IMPLIED>

    <!ELEMENT create (arg*)>
    <!ATTLIST create classname CDATA #REQUIRED>
    <!ATTLIST create objectname CDATA #IMPLIED>
    <!ATTLIST create loadername CDATA #IMPLIED>

    <!ELEMENT object (call | new)>
    <!ATTLIST object objectid CDATA #REQUIRED>

    <!ELEMENT new (arg*)>
    <!ATTLIST new classname CDATA #REQUIRED>

    <!ELEMENT register (arg*)>
    <!ATTLIST register objectname CDATA #IMPLIED>

    <!ELEMENT unregister EMPTY>
    <!ATTLIST unregister objectname CDATA #REQUIRED>

    <!ELEMENT arg (call | new | #PCDATA)>
    <!ATTLIST arg type CDATA #REQUIRED>

## Dynamic MBeans

## AbstractDynamicMBean base class for DynamicMBean implementation

Writing an MBean by implementing the `javax.management.DynamicMBean` interface can be a heavy and tedious task.

MX4J provides the class `mx4j.AbstractDynamicMBean` as a base class to implement a dynamic MBean. This class handles most of the tedious work that must be done when implementing dynamic MBeans, so that the MBean implementor has just to override few methods to provide the needed information required to create the MBean.

The methods of the `AbstractDynamicMBean` class can be divided in 2 groups: the methods of the `DynamicMBean` interface and the methods added by `AbstractDynamicMBean` itself.

`AbstractDynamicMBean` already implements all the methods of the `DynamicMBean` interface, and normally the MBean implementor does not have to override them. The methods belonging to the second group are normally overridden by the MBean implementor to provide the MBean metadata information, and are the following:

- `createMBeanAttributeInfo` , if the MBeans has manageable attributes
- `createMBeanOperationInfo` , if the MBeans has manageable operations
- `createMBeanNotificationInfo` , if the MBeans has manageable notifications
- `createMBeanConstructorInfo` , if the MBeans has manageable constructors
- `getMBeanDescription`

A third group of methods belongs to the subclass of `AbstractDynamicMBean` and are the implementation methods, the ones that implement the functionality of the MBean itself (see below for an example).

### Subclassing `AbstractDynamicMBean`

    public class SimpleDynamic extends AbstractDynamicMBean
    {
       /* Method of the second group that is overridden */
       protected MBeanAttributeInfo[] createMBeanAttributeInfo()
       {
          return new MBeanAttributeInfo[]
          {
             new MBeanAttributeInfo("Name", String.class.getName(), "The name", true, true, false)
          };
       }

       /* Method of the second group that is overridden */
       protected String getMBeanDescription()
       {
          return "A simple DynamicMBean";
       }

       /* Method of the third group that implements the MBean functionality */
       public String getName() { ... }

       /* Method of the third group that implements the MBean functionality */
       public void setName(String name) { ... }
    }

As you can see above, no methods from the `DynamicMBean` interface needs to be implemented. It is sufficient to override some (or all) of the methods of the second group, and provide the relative methods of the third group.

Normally the MBean implementor extends `AbstractDynamicMBean`, but if the MBean already extends another class it is sufficient to implement `DynamicMBean` and delegate to a subclass of `AbstractDynamicMBean`, having care of calling the `setResource` method (see example below).

### Delegating to `AbstractDynamicMBean` subclass

    public class ComposedDynamic extends MyBaseClass implements DynamicMBean
    {
       /* Create an AbstractDynamicMBean subclass */
       private AbstractDynamicMBean delegate = new AbstractDynamicMBean()
       {
          protected MBeanAttributeInfo[] createMBeanAttributeInfo()
          {
             return new MBeanAttributeInfo[]
             {
                new MBeanAttributeInfo("Status", int.class.getName(), "The status", true, true, false),
                new MBeanAttributeInfo("Enabled", boolean.class.getName(), "The enable status", true, false, true)
             };
          }

          protected MBeanOperationInfo[] createMBeanOperationInfo()
          {
             return new MBeanOperationInfo[]
             {
                new MBeanOperationInfo("enable", "Enables this MBean", new MBeanParameterInfo[0], Void.class.getName(), MBeanOperationInfo.ACTION),
                new MBeanOperationInfo("disable", "Disables this MBean", new MBeanParameterInfo[0], Void.class.getName(), MBeanOperationInfo.ACTION)
             };
          }
       };

       private int status;
       private boolean enabled;

       public ComposedDynamicMBean()
       {
          // Set the actual resource
          delegate.setResource(this);
       }

       /* Implement the methods of DynamicMBean interface to delegate to the AbstractDynamicMBean subclass */

       public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException
       {
          return delegate.getAttribute(attribute);
       }

       // Do the same with all other methods of DynamicMBean interface
       ...

       /* Methods of the third group that implements MBean functionality */

       public void setStatus(int status)
       {
          this.status = status;
       }

       public int getStatus()
       {
          return status;
       }

       public boolean isEnabled()
       {
          return this.enabled;
       }

       public void enable()
       {
          this.enabled = true;
       }

       public void disable()
       {
          this.enabled = false;
       }
    }

`AbstractDynamicMBean` can also be used for non-invasive management: if you already have a component but you don't want to change it to implement a management interface, you can set it as target of a subclass of `AbstractDynamicMBean` and provide the suitable metadata information.

### Subclassing `AbstractDynamicMBean`

    public class NonInvasiveDynamic extends AbstractDynamicMBean
    {
       /* Methods of the second group that are overridden */
       protected MBeanOperationInfo[] createMBeanOperationInfo()
       {
          return new MBeanOperationInfo[]
          {
             new MBeanOperationInfo("start", "Starts this MBean", new MBeanParameterInfo[0], Void.class.getName(), MBeanOperationInfo.ACTION),
             new MBeanOperationInfo("stop", "Stops this MBean", new MBeanParameterInfo[0], Void.class.getName(), MBeanOperationInfo.ACTION)
          };
       }

       protected String getMBeanDescription()
       {
          return "A non invasive DynamicMBean that manages resource";
       }

       /* Constructor that takes the managed resource */
       public NonInvasiveDynamic(ExternalService service)
       {
          // Set the actual resource that this MBean represents.
          setresource(service);
       }

    /* Old main, before JMX
       public static void main(String[] args) throws Exception
       {
          // Create the service
          ExternalService service = new ExternalService();

          // Start the service
          service.start();
       }
    */
       public static void main(String[] args) throws Exception
       {
          // Create the service
          ExternalService service = new ExternalService();

          MBeanServer server = MBeanServerFactory.createMBeanServer();
          NonInvasiveDynamic mbean = new NonInvasiveDynamic(service);
          ObjectName name = new ObjectName("domain:key=value");
          server.registerMBean(mbean, name);

          // Now start the service via JMX:
          // Few lines more, but now the service is manageable !
          server.invoke(name, "start", null, null);
       }
    }

The example above shows how simple can be to plug JMX into already existing architectures, and how it is possible, in few lines of code, to make services manageable (and remotely manageable with JSR 160) without even impacting already existing service's code.

## Naming MBeans

MX4J ships with two naming MBeans, the NamingService and the CosNamingService, that wrap as MBeans respectively the rmiregistry and the tnameserv tools provided with the JDK.

## The NamingService MBean

The NamingService MBean allows you to start the rmiregistry in the same JVM as other MBeans, such as the RMI MBean (see examples in the documentation), or the RMI adaptor. The MBean's class is `mx4j.tools.naming.NamingService`.

The usage of the NamingService MBean does not require additional libraries, as all the needed classes are already shipped with the JDK.

### Deployment

The NamingService MBean is easily deployed into a JMX Agent. The following code snippet shows how to deploy it into a JMX Agent.

#### Deploying the NamingService MBean

    MBeanServer server = MBeanServerFactory.createMBeanServer();
    ObjectName naming = new ObjectName("Naming:type=registry");
    server.createMBean("mx4j.tools.naming.NamingService", naming, null);

To use the NamingService MBean as rmiregistry, it must be started; the NamingService MBean can be started and stopped at wish, simply by invoking the `start()` and `stop()` methods of the management interface.

#### Starting and stopping the NamingService MBean

    Object proxy = MBeanServerInvocationHandler.newProxyInstance(server, naming, NamingServiceMBean.class, false);
    NamingServiceMBean mbean = (NamingServiceMBean)proxy;
    mbean.start();
    ...
    mbean.stop();

    or using the MBeanServer:

    server.invoke(naming, "start", new Object[0], new String[0]);
    ...
    server.invoke(naming, "stop", new Object[0], new String[0]);

It is also possible to specify the port on which the rmiregistry will run. Simply pass this parameter to the constructor of the NamingService MBean. By default the rmiregistry runs on port 1099.

#### Changing the default port

    MBeanServer server = MBeanServerFactory.createMBeanServer();
    ObjectName naming = new ObjectName("Naming:type=registry");

    server.createMBean("mx4j.tools.naming.NamingService", naming, null, new Object[] {new Integer(2099)}, new String[] {"int"});

    or

    NamingService mbean = new NamingService(3099);
    server.registerMBean(mbean, naming);

    or via MLet file (specify the suitable codebase)

    <MLET CODE="mx4j.tools.naming.NamingService"
          ARCHIVE="mx4j-tools.jar"
          CODEBASE="../lib/">
       <ARG TYPE="int" VALUE="4099">
    </MLET>

It is also possible to change the rmiregistry port at runtime. Just start the NamingService MBean, stop it after a while, change the port it runs on, and restarting it, so that it will accept requests on the new port. Below you can see the steps needed to perform this change.

#### Changing the port at runtime

    MBeanServer server = MBeanServerFactory.createMBeanServer();
    ObjectName naming = new ObjectName("Naming:type=registry");
    server.createMBean("mx4j.tools.naming.NamingService", naming, null);
    Object proxy = MBeanServerInvocationHandler.newProxyInstance(server, naming, NamingServiceMBean.class, false);
    NamingServiceMBean mbean = (NamingServiceMBean)proxy;

    mbean.start();
    ...
    mbean.stop();
    mbean.setPort(5099);
    mbean.start();

## The CosNamingService MBean

The CosNamingService MBean is very similar to the NamingService MBean: it allows you to start tnameserv in the same JVM as other MBeans. The MBean's class is `mx4j.tools.naming.CosNamingService`.

The usage of the CosNamingService MBean does not require additional libraries, as all the needed classes are already shipped with the JDK.

### Deployment

The CosNamingService MBean is easily deployed into a JMX Agent, in a way very similar to the NamingService MBean.

Exactly like the NamingService MBean, the CosNamingService MBean must be first registered in the MBeanServer and then started using the management interface it exposes. There is the possibility to set the port on which the service will listen for incoming connections, exactly like the NamingService MBean.

One difference between the CosNamingService and the NamingService MBeans is that the latter provides and easy API to be implemented, so that creating, starting and stopping it can be implemented easily by the MX4J team, while the former does not.

A consequence of this is that tnameserv is started using `Runtime.exec()` and stopped by killing the process created when starting the MBean.

Since starting and stopping an external process may result in the `start` and `stop` returning before the process is really started (or stopped), it is recommended to sleep some time after start() and stop() in order to let tnameserv to start and stop completely. A suggested value for this delay may be few seconds (1000-5000 milliseconds), but the value strongly depends on the hardware and operative system.

## Mailer MBean

## Introduction

The SMTP MBean is meant to be used to send emails from your JMX application. The MBean's class is `mx4j.tools.mail.SMTP`.

You can use it in basically two ways:

- Directly by calling the sendMail method

- By listening notifications, for instance from a Timer or Monitor

The usage of the MBean requires that you have JavaMail and the Java Activation Framework. The MBean has been tested with JavaMail 1.2 and JAF 1.0.1.

## Configuration

The MBean has quite many attributes to work but as a minimum you should set up the serverHost and To. After that you can start sending emails.

If your server requires authentication, set the LoginToServer attribute to true and fill the ServerUserName and ServerPassword fields

You can also set the source address by setting the FromAddress field as well as the FromName field. The destination attributes can be set setting a comma separated list of addresses by using the To, Cc and Bcc attributes. The addresses are not checked until a mail is actually sent, but in case some are not well formed, to those who are will be sent anyway

To make the MBean to listen for notifications set the ObservedObject field. The SMTPMBean will register iteself as listener of that MBean and when a notification is received it will send the mail. If you set the NotificationName field, only notification names with that type will be valid to send a mail. For instance "javax.management.monitor.string.differ"

## Keyword expanding

To make the content of the mail more customizable you can include keyword expansion on the Subject, and Content field. The keywords are special words set in between of $ signs. e.g. $date$. Those keywords will be replaced before the mail is sent, so you can get text containing more information. The recognized keywords are:

- $date$ Expands to the current date formatted with locale format

- $time$ Expands to the current time formatted with locale format

- $datetime$ Expands to the current datetime formatted with locale format

- $observed$ Expands to the observed MBean's ObjectName which triggered the mail

- $notification$ Expands to the notification type which triggered the mail

- $objectname$ Expands to the SMTPMBean's ObjectName

## Jython MBean

## Introduction

The JythonRunner MBean can be used to execute jython scripts. The main objective is to use them for management tasks which are easiliy handled as scripts and that could be modified and deployed at runtime. The MBean's class is `mx4j.tools.jython.JythonRunner`.

You can use it in two ways:

- By calling the runScript method

- By listening notifications, for instance from a Timer or Monitor

The usage of the MBean requires that you have jython installed. You can get a copy at http://www.jython.org. Jython is distributed (as version 2.1) on a class file which is the installer and once execute will install the jython distribution, e.g. at /usr/local/jython-2.1 or C:\Java\jython-2.1. Jython can be run in two different ways depending on whether you want to use the jython standard library.

If you want to use the standard librarie, add the jython.jar as in the installation dir to the classpath. e.g.

java -cp /usr/local/jython-2.1/jython.jar:mx4j-jmx.jar:mx4j-tools.jar

In this way jython will be able to find the install dir and load the libraries from there. You can get the same effect by passing a python.path variable as:

java -Dpython.path=/usr/local/jython-2.1 -cp jython.jar:mx4j-jmx.jar:mx4j-tools.jar

If you don't need the standard libraries (and that can be the case for many JMX tasks, it is enough to have the jython.jar in your system classpath

## Configuration

The MBean has a few parameters which can be used to configure the MBean. This includes the ObservedObjectName and Notification Name used to configure the MBean to listen for notifications. The Script and ScriptFile parameters point to the content of the script. For simple scripts you could just use the Script parameter. For morke comple scripts you are better of pointing to a file. The ScriptFile is actually a URL and therefore can point to http locations

## Built-in functions

To ease the script constructions some variables, class and functions are readily available to your script. The most important one is server which point to the current MBean server. The server variable IS a MBeanServer object and all methods are valid. You can write scripts like:

                # write all the "test:name=test" mbean operations
                [print operation for operation in server.getMBeanInfo(ObjectName("test:name=test")).operations]

Aditionally all the javax.management.* class are imported making objects like ObjectName or Attribute already available.

There are also some utility functions and classes:

- `proxy` The proxy class wraps a objectname making it easier to access (It is equivalent to the MBeanServerInvocationHandler class). You can directly retrieve and modify attributes and invoke mathods. For instance:

                           #
                           # Assume the MBean with ObjectName Test:name=jython has name and time attributes and a method start()
                           #
                           o = ObjectName("Test:name=jython")
                           p = proxy(o)
                           # you can access functions directly
                           print p.name
                           p.time = 12343
                           # also works with functions
                           p.start()

- `mbeans(query)` Returns a list of the mbeans in the server which are in the query. The query is of the form "*:*". It can be omited and the function will return all the mbeans

- `instances(classname, query)` Returns a list of the mbeans in the server which are instances of classname. The server accepts also an optional query method.