The agent is the central component of the JMX management architecture. An agent contains MBeans and hides their implementation behind a standardized management interface, it lets management applications connect and interact with all MBeans, and it provides filtering for handling large numbers of MBeans.
Java Dynamic Management agents are dynamic because resources can be added and removed, connections can be closed and reopened with a different protocol, and services can be added and removed as management needs evolve. Resources, management services and remote connectivity are all handled by MBean objects. This creates a very homogeneous model where an agent is a framework containing MBeans of different sorts and allowing them to interact.
The main component of an agent is the MBean server: it registers all MBeans in the agent and exposes them for management. The role of the MBean server is to be the liaison between any object available to be managed and any object with a management request. Usually resource MBeans are managed either by remote applications through connectivity MBeans or by local agent service MBeans. This model allows connectors and services to also be created, modified or removed dynamically.
This lesson focuses on the functionality of the MBean server and the Java objects which are needed to create a simple agent. Details about programming managers and about using connectors and services will be covered later.
This lesson contains the following topics:
"The MBean Server in a Minimal Agent" covers the interface of the MBean server which is used by all agents. We introduce the object name of an MBean which is its only reference in the MBean server. The only MBeans in the minimal agent are the communications MBeans, but this is enough to connect to the agent and manage it.
"The HTML Protocol Adaptor" gives us a management view of the MBeans in an agent through a web browser. It lets us create MBeans, update their attributes, invoke their operations, and remove them dynamically in a running agent.
"The Base Agent" is similar to the minimal agent but it shows how to manipulate MBeans programmatically through the instance of the MBean server. It covers the different ways of creating and interacting with MBeans in the MBean server. This topic also covers how to process the descriptor objects that represent an MBean's management interface.
An agent application is a program written in the Java language which contains an MBean server and some way of accessing its functionality. This would be a minimal agent, anything less couldn't be managed. In our example of a minimal agent, we will access the MBean server through the HTML protocol adaptor from a web browser.
In a real management solution, the agent could be instantiated and loaded with MBeans for all services and resources that it might need when launched. However, a minimal agent might also be used when resources and services are unknown at launch time. They would be instantiated dynamically at a later date by some management application connected to the agent. This flexibility shows how the Java Dynamic Management Kit lets you develop many different management solutions, depending on your intended deployment strategy.
For now we will focus on the functionality of the MBean server and how to interact with it through the HTML protocol adaptor. The code samples in this chapter are taken from the files in the MinimalAgent example directory located in the main examplesDir (see "Directories and Classpath" in the preface).
Contents:
"MBean Server Classes" explains the interfaces of the MBean server classes.
"The Minimal Agent" shows the code needed to write an agent application.
"Referencing MBeans" covers the objects used to reference an MBean in an agent.
"A Minimalist Agent" shows the code for a very small but complete agent.
"Running the Minimal Agent Example" demonstrates its run-time behavior.
Before writing an agent application, it is important to understand the functionality of the MBean server. It is actually an interface and a factory object defined by the agent specification level of the Java Management extensions. The Java Dynamic Management Kit provides an implementation of this interface and factory. The factory object finds or creates the MBean server instance, making it possible to substitute different implementations of the MBean server.
The specification of the interface defines all operations that can be applied to resources and other agent objects through the MBean server. Its methods can be divided into three main groups:
Methods for controlling MBean instances:
createMBean, or instantiate and registerMBean add a new MBean to the agent
unregisterMBean removes an MBean from the agent
isRegistered and getObjectInstance associate the class name with the MBean's management name
addNotificationListener and removeNotificationListener control event listeners for a particular MBean
deserialize is used to download new MBean classes
Methods for accessing MBean attributes and operations; these methods are identical to those presented in "The DynamicMBean Interface", except they all have an extra parameter for specifying the target MBean:
getMBeanInfo
getAttribute and getAttributes
setAttribute and setAttributes
invoke
Methods for managing the agent as a whole:
getDefaultDomain (domains are a way of grouping MBeans in the agent)
getMBeanCount of all MBeans in an agent
queryMBeans and queryNames are used to find MBeans by name or by value
The MBeanServerImpl class in the Java Dynamic Management Kit implements the MBeanServer interface. It is the class that will be instantiated in an agent. However, it is never instantiated directly by the agent application. Instead, you rely on the MBean server factory to return a new instance of the implementing class.
The MBeanServerFactory is a static class defined by the Java Management extensions that makes the agent application independent of the MBean server implementation. It resides in the Java virtual machine and centralizes all MBean server instantiation. It provides two static methods:
createMBeanServer which returns a new MBean server instance
findMBeanServer which returns a list of MBean servers in the Java virtual machine
You must use this class to create an MBean server so that other objects can obtain its reference by calling the findMBeanServer method. This method allows dynamically loaded objects to find the MBean server in an agent which has already been launched.
The minimal agent contains only the essential components of a complete agent application. These are:
An instance of the MBean server
Some means of communication
The following code is the complete application from the MinimalAgent.java file:
import javax.management.ObjectInstance; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; public class MinimalAgent { public static void main(String[] args) { // Instantiate the MBean server System.out.println("\nCreate the MBean server"); MBeanServer server = MBeanServerFactory.createMBeanServer(); // Create and start some way of communicating: // - an HTML protocol adaptor // - an HTTP connector server // - an RMI connector server // Any single one of these would be sufficient try { System.out.println( "\nCreate and start an HTML protocol adaptor"); ObjectInstance html = server.createMBean( "com.sun.jdmk.comm.HtmlAdaptorServer", null); server.invoke(html.getObjectName(), "start", new Object[0], new String[0]); System.out.println( "\nCreate and start an HTTP connector server"); ObjectInstance http = server.createMBean( "com.sun.jdmk.comm.HttpConnectorServer", null); server.invoke(http.getObjectName(), "start", new Object[0], new String[0]); System.out.println( "\nCreate and start an RMI connector server"); ObjectInstance rmi = server.createMBean( "com.sun.jdmk.comm.RmiConnectorServer", null); server.invoke(rmi.getObjectName(), "start", new Object[0], new String[0]); } catch(Exception e) { e.printStackTrace(); return; } System.out.println( "\nNow, you can point your browser to http://localhost:8082/"); System.out.println( "or start your management application to connect to this agent.\n"); } } |
Here we analyze the most important lines of code in this example. We start with the instantiation of the MBean server:
MBeanServer server = MBeanServerFactory.createMBeanServer();
The MBean server is created through the static MBeanServerFactory object, and we store its object reference. Its true type is hidden by the factory object, which casts the returned object as an MBeanServer interface. The MBean server is the only functional class referenced directly in this application.
Then we just need some means of communicating (only the HTML adaptor is shown here):
ObjectInstance html = server.createMBean("com.sun.jdmk.comm.HtmlAdaptorServer", null); server.invoke(html.getObjectName(), "start", new Object[0], new String[0]);
For each of the communications protocols we ask the MBean server to create the corresponding MBean. We must provide the class name of the MBean which we want the MBean server to instantiate. The MBean server instantiates the object, registers it for management, and returns its ObjectInstance reference (see "The ObjectInstance of an MBean").
When an MBean is created through the MBean server, you can never obtain a direct programmatic reference on an MBean. The object instance is the only handle the caller has on the MBean. The MBean server hides the MBean object instance and only exposes its management interface.
We then ask the server to invoke the start operation of the HTML adaptor's MBean. The object instance gives us the MBean's object name which is what we use to identify the MBean (see "Object Names"). The other parameters correspond to the signature of the start operation which takes no parameters. This operation activates the adaptor or connector so that it will respond to remote management operations on its default port. We can now connect to the HTML protocol adaptor from a web browser.
As demonstrated by the minimal agent, most agent applications interact with MBeans through the MBean server. It is possible for an object to instantiate an MBean class itself which it can then register in the MBean server. In this case, it may keep a programmatic reference to the MBean instance. All other objects can only interact with the MBean through its management interface exposed by the MBean server.
In particular, service MBeans and connectivity MBeans rely solely on the MBean server to access resources. The MBean server centralizes the access to all MBeans: it unburdens all other objects from having to keep numerous object references. To insure this function, the MBean server relies on object names to uniquely identify MBean instances.
Each MBean object registered in the MBean server is identified by an object name. The same MBean class can have multiple instances, but each must have a unique name. The ObjectName class encapsulates an object name which is composed of a domain name and a set of key properties. The object name can be represented as a string in the following format:
DomainName:property=value[,property2=value2]* |
The DomainName, the properties and their values can be any alpha-numeric string, so long as they don't contain any of the following characters: : , = * ?. All elements of the object name are treated as literal strings, meaning that they are case sensitive.
A domain is an abstract category that can be used to group MBeans arbitrarily. The MBean server lets you easily search for all MBeans with the same domain. For example, all connectivity MBeans in the minimal server could have been registered into a domain called Communications.
Since all object names must have a domain, the MBeans in an MBean server necessarily define at least one domain. When the domain name is not important, the MBean server provides a default domain name which you can use. By default, it is called the DefaultDomain, but you may specify a different default domain name when creating the MBean server from its factory.
A key is a property-value pair that can also have any meaning that you assign to it. An object name must have at least one key. Keys and their values are independent of the MBean's attributes: the object name is a static identifier which should identify the MBean, whereas attributes are the exposed, run-time values of the corresponding resource. Keys are not positional and can be given in any order to identify an MBean.
Keys usually provide the specificity for identifying a unique MBean instance. For example, a better object name for the HTML protocol adaptor MBean might be: Communications:protocol=html,port=8082, assuming the port will not change.
All MBeans must be given an object name that is unique. It can be assigned by the MBean's pre-registration method, if the MBean supports the pre-registration mechanism. Or it can be assigned by the object which creates or registers the MBean, which overrides the one given during pre-registration. However, if neither of these assign an object name, the MBean server will not create the MBean and raise an exception. Once an MBean is instantiated and registered, its assigned object name cannot be modified.
You are free to encode any meaning into the domain and key strings, the MBean server just handles them as literal strings. The contents of the object name should be determined by your management needs. Keys could be meaningless serial numbers if MBeans are always handled programmatically. On the other hand, the keys could be human-readable to simplify their translation to the graphical user interface of a management application. With the HTML protocol adaptor, object names are displayed directly to the user.
An object instance represents the complete reference of an MBean in the MBean server. It contains the MBean's object name and its Java class name. Object instances are returned by the MBean server when an MBean is created or in response to queries about MBeans. Since the object name and class name cannot change over the life of a given MBean, its returned object instance will always have the same value.
You cannot modify the class or object name in an object instance, this information can only be read. The object name is used to refer to the MBean instance in any management operation through the MBean server. The class name may be used to instantiate similar MBeans or introspect characteristics of the class.
The following code is one of the smaller agents you can write. It retains all of the functionality that we will need to connect to it with a web browser in the next topic ("The HTML Protocol Adaptor").
import javax.management.ObjectInstance; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; public class MinimalistAgent { public static void main(String[] args) { MBeanServer server = MBeanServerFactory.createMBeanServer(); try { ObjectInstance html = server.createMBean( "com.sun.jdmk.comm.HtmlAdaptorServer", null); server.invoke(html.getObjectName(), "start", null, null); } catch(Exception e) { e.printStackTrace(); return; } } } |
Only three classes are "imported" by this program and needed to compile it. However, the MBean server dynamically instantiates other classes such as the HtmlAdaptorServer which are needed at run-time. As a result, the Java Dynamic Management Kit runtime jar file (jdmkrt.jar) must be in the classpath of the Java virtual machine running the minimal agent.
The MinimalistAgent relies on the HTML adaptor, but we could have used any MBean that provides some way of accessing the MBean server. You could even use your own MBean that encodes some proprietary protocol, provided it makes all functionality of the MBean server available remotely.
It is important to realize that this minimalist agent is a fully functional agent that is every bit as powerful as any agent that may be deployed. Since we can connect to this agent, we can dynamically create new MBeans for it to manage, and classes that aren't available locally can be downloaded from the network (this is covered in "The M-Let Class Loader"). Because resources, services and other connections may be added on-the-fly, this agent can participate in any management scheme.
Of course, it is more efficient for the agent application to perform the initialization, including the creation of all MBeans that are known to be necessary. Typically, an agent application also needs to set up data structures or launch specific applications that its resources require. For example, it may establish a database session that an MBean will use to expose stored information. The agent application usually includes everything necessary for making the intended resources ready to be managed within the intended management solution.
However, there is no single management solution. Many different agent applications could perform the same management function, requiring more or less intervention after they are launched. And the flexibility of the Java Dynamic Management Kit means that there are many different management solutions to achieve the same goal. For example, an MBean could also establish the database session itself during its registration phase.
The example code for the MinimalAgent application is located in the examplesDir/MinimalAgent directory. As we saw, this agent application only has minimal output and is intended to be accessed for management through one of its communications MBeans. However, you will need to compile and launch the minimal agent if you continue on to the next topic.
Compile the MinimalAgent.java file in this directory with the javac command. For example, on the Solaris platform, you would type:
$ cd examplesDir/MinimalAgent/ $ javac -classpath classpath *.java |
When we access the minimal agent through the HTML adaptor, we will instantiate the SimpleStandard and SimpleDynamic classes. Since we don't use a dynamic class loader, the agent will need these classes at runtime. You will need to have compiled the standard and dynamic MBean classes as described in "Running the Standard MBean Example" and "Running the Dynamic MBean Example". To run the example, update your classpath to find the MBeans and launch the agent class:
$ java -classpath classpath:../StandardMBean:../DynamicMBean MinimalAgent |
This being a minimal agent, the example doesn't have much output. The MBean server is launched, and the three communication MBeans are created: it is now possible to connect to this agent. The HTTP and RMI connector servers communicate with connector clients in manager applications.
The simplest way to communicate with the agent is through the HTML protocol adaptor. This adaptor provides a view of the agent and its MBeans through standard HTML pages which can be viewed on almost any web browser. To connect to the agent, load the following URL in your browser:
If you get an error, you may have to switch off proxies in your preference settings or substitute your machine name for localhost. Any browser on your local network can also connect to this agent by using your machine name in this URL. In the next topic, "The HTML Protocol Adaptor", we will go into the details of managing this agent from its web view.
The HTML protocol adaptor provides a view of the agent and its registered MBeans through a basic interface on any web browser. It is the easiest way to access an agent since no further coding is necessary. For this reason, it can be useful for testing and debugging your MBeans in the minimal agent.
In fact, we will use your browser to "manage" the minimal agent and its MBeans. The HTML protocol adaptor outputs HTML pages which represent the agent and its MBeans. The adaptor also interprets the commands sent back by the buttons and fields appearing in your browser. It then interacts with the agent's MBean server in order to get information about the MBeans that it has registered and operate on them.
The HTML adaptor relies mostly on plain HTML. The only JavaScriptTM that the generated pages contain are pop-up windows for displaying information. Browsers that are not JavaScript enabled might give an incompatibility message and won't be able to display the information. Otherwise, the generated pages contain no further scripting (JavaScript, Visual Basic or other), no frames and no images that might slow down loading.
This topic relies on the minimal agent which you will need to launch first, as explained in "Running the Minimal Agent Example". Once you can connect to the HTML protocol adaptor in the minimal agent, you are ready to go through these topics:
"The Agent View" is the main page for managing an agent through the HTML protocol adaptor.
"The MBean View" exposes an MBean's management interface.
The "Agent Administration" lets you instantiate new MBeans.
"Instantiating and Managing MBeans" shows how to modify attributes and invoke operations.
"Filtering MBeans" is used to select the MBeans displayed in the agent view.
The first page displayed by the HTML adaptor is always the agent view. It originally contains a list of all registered MBeans. The following figure shows the agent view for the minimal agent. It contains four MBeans: the three communication MBeans, one of which is the HTML adaptor, and the MBean server delegate. The delegate is a special MBean covered in "The MBean Server Delegate".
The text field for filtering by object name lets you modify the list of displayed MBeans. The filter string is initially *:*, which gives all registered MBeans. Further use of the filter is covered in "Filtering MBeans". The agent's registered domain tells you the name of the default domain in this agent. The number of MBeans on this page is the count of those listed beneath the separator line.
The "Admin" button is a link to the agent administration page which we will cover in "Agent Administration".
The MBean list contains all MBeans whose object name matches the filter string. Object names can be filtered by their domain name and list of key-value pairs. In this list, MBeans are sorted and grouped by their domain name. Each MBean name listed is an active link to the page of the corresponding MBean view.
After its initialization, the contents of an agent are dynamic: new MBeans may be created and registered into new or existing domains and old MBeans may be removed. These changes can also affect the functionality of the agent: new agent services may be registered (or removed) as well. We will demonstrate examples of dynamic management in "Instantiating and Managing MBeans".
The MBean server delegate is an MBean that is automatically instantiated and registered by the MBean server when it is created. It provides information about the version of the Java Dynamic Management Kit which is running, and it represents the MBean server when sending notifications.
Notifications are events sent by MBeans, they are covered in detail in the lesson on "Notification Mechanisms." Since the MBean server instance is not an MBean object, it relies on its delegate MBean to send notifications. The MBean server delegate sends notifications to inform interested listeners about such events as MBean registrations and de-registrations.
The exposed attributes of the delegate MBean provide vendor and version information about the MBean server. This can let a remote management application know which agent version is running and which version of the Java Runtime Environment it is using. The delegate MBean also provides a unique identification string for its MBean server.
Click on the name of the delegate MBean to see its attributes. Version, vendor and identification information is listed in the table of attributes.
Click on the Back to Agent View link or use your browser's Previous page function to return to the MBean list in the agent view.
The MBean view has two functions: it presents the management interface of the MBean and it lets you interact with its instance. The management interface of an MBean is given through the name of the attributes, the operation signatures, and a self-description. You may interact with the MBean by reloading its attribute values, setting new values or invoking an operation.
In the agent view, click on the object name of the HTML adaptor MBean: name=HTMLAdaptorServer in the default domain. This will bring up its MBean view.
As shown in the following figure, the top part of the page contains the description of the MBean and some controls for managing it:
The first two lines give the object instance (object name and class name) for this MBean. The MBean name is the full object name of this MBean instance, including the domain. The key-property pairs may or may not identify the MBean to a human reader, depending on the agent developer's intention. The MBean Java class is the full class name for the Java object of which this MBean is an instance.
The reload controls include a text field for entering a reload period and a manual "Reload" button. Originally, the reload period is set to zero indicating that the contents of the MBean view are not automatically refreshed. Clicking the reload button will force the page to reload, thereby updating all of the attribute values displayed. If you have entered a reload period, clicking the button will begin automatic reloading with the given period. The reload period must be at least five seconds.
You should use the reload button of the MBean view instead of the browser's reload-page button. After some operations, such as applying changes to attribute values, the browser's button will repost the form data, inadvertently performing the same operation again. To avoid undesirable side effects, always use the reload button provided in the MBean view.
Enter a reload period of five and click the "Reload" button. Every five seconds the page will blink as it reloads.
In another browser window, open another connection to the HTML adaptor at http://localhost:8082/. Observe the new values for the ActiveClientCount and LastConnectedClient attributes in the original window. Due to the way the adaptor works, you may have to try several connections before you see the attribute values change.
The reload period is reset to zero every time you open an MBean view.
The "Unregister" button is a shortcut for removing this MBean from the agent. Unregistering is covered in "Instantiating and Managing MBeans".
The MBean description text provides some information about the MBean. Because standard MBeans are statically defined, they cannot describe themselves, and the MBean server provides a generic text. Dynamic MBeans are required to provide their own description string at runtime according to the JMX specification. Except for the class name, this is the only way to tell standard and dynamic MBeans apart in the MBean view.
The second part of the MBean view is a table containing all attributes exposed by the MBean. For each attribute, this table lists its name, its Java type, its read-write access and a string representation of its current value.
While MBean attributes may be of any type, not all types can be displayed in the MBean view. The HTML adaptor is limited to basic data types that can be displayed and entered as strings. Read-only attributes whose type support the toString method are also displayed. Enumerated types that are concrete subclasses of com.sun.jdmk.Enumerated are displayed as a menu with a pop-up selection list. Boolean attributes are represented as true-false radio buttons. Finally, attributes with array types are represented by a link to a page which displays the array values in a table. If the attribute is writeable, you may enter values for the array elements to set them.
For the complete list of supported types, see the Javadoc API of the HtmlAdaptorServer class. If an attribute type is not supported, this is mentioned in place of its value. If there was an error when reading an attribute's value, the table contains the name of the exception that was raised and the message it contains.
The name of each attribute is a link that pops up a dialog box containing the description for this attribute. Like the MBean description, attribute descriptions can only be provided by dynamic MBeans. The MBean server inserts a generic message for standard MBean attributes. The following figure shows the attributes of the HTML adaptor with a description of the Active attribute:
Click on the attribute names of the HTML adaptor to read their description. Since the HTML adaptor is implemented as a dynamic MBean, its attribute descriptions are meaningful.
Due to the use of JavaScript commands in the generated HTML, these pop-up windows might not be available on browsers that are not JavaScript-enabled.
Writable attributes have a text field for entering new values. To set the value of a writable attribute, you would enter or replace its current value in the text field and click the "Apply" button at the bottom of the attributes table.
You should not try to modify the attributes of the HTML protocol adaptor here, we will see why in "Instantiating and Managing MBeans".
Because there is only one "Apply" button for all attributes, this button has a particular behavior: it systematically invokes the setter for all writeable attributes, whether or not their field has actually been modified. This may impact the MBean if setters have side effects, such as counting the number of modifications as in the SimpleStandard and SimpleDynamic examples given in "Instrumentation through MBeans."
The HTML adaptor detects attributes which are ObjectName types and provides a link to the MBean view of the corresponding MBean. This link is labeled view, and it is located just under the displayed value of the object name. Since MBeans often need to reference other MBeans, this provides a quick way of navigating through MBean hierarchies.
The last part of the MBean view contains all of the operations exposed by the MBean. Each operation in the list is presented like a method signature: there is a return type, then a button with the operation name, and if applicable, a list of parameters, each with their type as well.
As with the table of attributes, the list of operations contains only those involving types that can be represented as strings. The return type must support the toString method and the type of each parameter must be one of basic data types supported by the HTML adaptor. For the complete list, see the Javadoc API of the HtmlAdaptorServer class.
Above each operation is a link to its description. Parameter names are also active links which pop up a window with a description text. Again, descriptions are only meaningful when provided by dynamic MBeans. The following figure shows some of the operations exposed by the HTML adaptor MBean and a description of the Start operation.
We will not invoke any operations on this MBean until a brief explanation in "Instantiating and Managing MBeans".
To invoke an operation, you would fill in any and all parameter values in the corresponding text fields and then click the operation's button. The HTML adaptor would then display a page with the result of the operation: the return value if successful or the reason the operation was unsuccessful.
Go back to the agent view by clicking the link near the top of the MBean view page. Then click on the "Admin" button in the agent view to bring up the agent administration page in your browser window.
The agent administration page contains a form for entering MBean information when creating or unregistering MBeans. You may also instantiate an MBean through one of its public constructors. In order to instantiate an MBean, its class must be available in the agent application's classpath. Optionally, you may specify a different class loader in the appropriate field if the agent contains other class loader MBeans.
The first two fields, "Domain" and "Keys" are mandatory for all administrative actions. The "Domain" field initially contains the string representing the agent's default domain. Together, these fields define the object name, whether for a new MBean to be created or the name of an existing MBean to unregister. The "Java Class" is the full class name of the object to be instantiated as a new MBean. This field is ignored when unregistering an MBean.
Using the drop-down menu, you may select one of three actions on this page:
Create - Instantiates the given Java class of an MBean and registers the new instance in the MBean server. If successful, the MBean will then appear in the agent view. The class must have a public constructor without parameters in order to be created in this way.
Unregister - Unregisters an MBean from the MBean server so that it is no longer available in the agent. The class instance is not explicitly deleted, though if no other references to it exist, it will be garbage collected.
Constructors - Displays the list of public constructors at the bottom of the administration page for the given Java class. This lets you provide parameters to a specific constructor and create the MBean in this manner. This is the only way to create MBeans which do not have a no-parameter constructor.
When you click the "Send Request" button, the HTML adaptor processes the action and updates the bottom of the page with the action results. You may have to scroll down to see the result. The text fields are not cleared after a request so that you can do multiple operations. The "Reset" button will return the fields to their last posted value after you have modified them.
Sometimes, launching an MBean requires several steps: this is particularly the case for agent services which require some sort of configuration. For example, you can instantiate another HTML adaptor for connecting to a different port. Usually, this would be done programmatically in the agent application, but we need to do it through the browser for the minimal agent.
On the agent administration page, fill in the fields as follows:
Domain: | Communications |
Keys: | protocol=html,port=8088 |
Java Class: | com.sun.jdmk.comm.HtmlAdaptorServer |
Class Loader: | leave blank |
Note: In previous versions of product, specifying the port number in the object name would initialize communication MBeans. Starting with the Java Dynamic Management Kit 4.0, the names and contents of key properties no longer have any significance for any components of the product. We must set the port in other ways.
Make sure the selected action is "Create" and send the request. If you scroll down the page, you should see if your request was successful.
We can't connect to this HTML adaptor quite yet, we need to configure it first.
Go to the new HTML adaptor's MBean view with the provided link.
We couldn't modify any of the adaptor's attributes before because the implementation is designed so that they can't be modified while it is on-line. Our new HTML adaptor is instantiated in the stopped state (the StateString attribute indicates "OFFLINE"), so we can change its attributes.
Set the Port attribute to "8088" and MaxActiveClientCount to "2", then click the "Apply" button. If the page is reloaded and the new values are displayed, the attribute write operation was successful. You may also click the attribute names to get an explanation for them.
Scroll down the MBean view to the Start operation and click its button. This brings up a new page to tell us the operation was successful. If you go back to the MBean view with the provided link, you can see that the StateString is now indicating ONLINE.
Now you should be able to access your minimal agent through a browser on port 8088. Try going to a different machine on the same network and connecting to the URL:
where agentHostName is the name or IP address of the machine where you launched the MinimalAgent. If you reload the MBean view of the new HTML adaptor on either browser, the name of this other machine should be the new value of the LastConnectedClient attribute.
Through this other connection, you could stop, modify or remove the HTML adaptor MBean using port 8082. In that case, your original browser will have to use http://localhost:8088/ as well to connect. Instead, we will manage the minimal agent from this other machine.
From the browser on the other machine, go to the administration page. Fill in the fields as follows and request the constructors:
Domain: | Standard_MBeans |
Keys: | name=SimpleStandard,number=1 |
Java Class: | SimpleStandard |
Class Loader: | leave blank |
The list of constructors for the SimpleStandard class is given at the bottom of the page. The MBean name is also given: this is the object name that will be assigned to the MBean when using one of the listed constructors. As you can see, the SimpleStandard class only has one constructor that takes no parameters.
Click on the "Create" button: the result will be appended to the bottom of the page. Scroll down and go to the MBean view with the provided link.
Since it is a standard MBean, all of its description strings are generic: this shows the necessity of programming meaningful attribute names.
In the agent view on the original browser window, click in the filter field and hit "Return" to refresh the agent view. Click on the new MBean's name and set its reload period to 15. Back on the other machine, type in a different string for the State attribute and click "Apply".
On the original machine, you should see the MBean's attributes get updated when the MBean view is periodically reloaded.
On the other machine, click the reset operation button at the bottom of the MBean view page. This brings up the operation result page which indicates the success of the operation.
This page also gives the return value of the operation when it is not void. If you go back to the MBean view, you will see the result of the operation on the attributes. You should also see it on the original machine after it reloads.
The browser on the other machine is no longer needed, and we can remove the HTML adaptor on port 8088.
Go to the administration page and fill in the object name of the HTML adaptor we want to remove (you don't need its Java class to unregister it):
Domain: | Communications |
Keys: | protocol=html,port=8088 |
Java Class: | leave blank |
Class Loader: | leave blank |
Select "Unregister" from the drop down menu and click the "Send Request" button. The result then appears at the bottom of the page.
You can also unregister an MBean directly from its MBean view: just click the "Unregister" button on the upper right hand-side of the page.
Since an agent can manage hundreds of MBeans, the agent view provides a filtering mechanism for the list that is displayed. An object name with wildcard characters is used as the filter, and only those MBeans which match are counted and displayed.
Go to the administration page, and create three more of the standard MBeans. Modify only the number value in their object name so that they are numbered sequentially. In the same way, create four dynamic MBeans starting with:
Domain: | Dynamic_MBeans |
Keys: | name=SimpleDynamic,number=1 |
Java Class: | SimpleDynamic |
Class Loader: | leave blank |
Go back to the agent view which should display all of the new MBeans.
Filters restrict the set of MBeans listed in the agent view. This may not be particularly useful for our small agent, but it can help you find MBeans among hundreds in a complex agent. In addition, management applications use the same filter syntax when requesting an agent's MBeans through the programmatic interface of a connector. The filtering lets managers get either lists of MBean names or find a particular MBean instance.
Filters are entered as partial object names with wild-card characters or as a full object name for which to search. Here are the basic substitution rules for filtering:
You may search for partial domain names:the asterisk (*) stands for any number (including zero) of any characters;the question mark (?) stands for any one character
An empty domain name stands for the default domain string;an empty key list is illegal
Keys are atomic: you must search for the full property=value key, you may not search for a partial property name or an incomplete value
The asterisk (*) may be used to terminate the key list, where it stands for any number of any keys (complete property-value pairs)
You must match all keys exactly: use the form property=value,* to search for one key in names with multiple keys
Keys are unordered when filtering: giving one or more keys (and an asterisk) finds all object names which contain that subset of keys
Enter the following filter strings to see the resulting MBean list:
Standard_MBeans:* | Gives all of the standard MBeans we created |
*_MBeans:* | Gives all of the standard and dynamic MBeans we created |
DefaultDomain: | Not allowed by rule 2 |
:* | Lists all MBeans in the default domain |
*:name=Simple*,* | Not allowed by rule 3 |
*:name=SimpleStandard | Allowed, but list is empty (rule 5) |
*:name=* | Not allowed by rule 3 |
*_??????:number=2,* | Gives the second standard and dynamic MBean we created |
Communications:port=8088,protocol=html | Gives the one MBean matching the domain and both (unordered) keys |
empty string | allowed: special case equivalent to *:* |
Notice how the MBean count is updated with each filter: this count gives the number of MBeans that were found with the current filter, which is the number of MBeans appearing on the page. It is not the total number of MBeans in the agent, unless the filter is *:*.
When you are ready to stop the minimal agent example, go to the window where you launched its class and type <Control-C>.
The base agent demonstrates the programming details of writing an agent application. We will cover how to access the MBean server, ask it to create MBeans, and then interact with those MBeans. Everything that we could do through the HTML adaptor can be done through the code of your agent application.
Interacting programmatically with the MBean server gives you more flexibility in your agent application. This topic covers the three main ways to create MBeans through the MBean server, how to interact with MBeans, and how to unregister them.
The base agent is functionally equivalent to the minimal agent, but instead of writing the smallest agent, we will demonstrate good defensive programming with error checking. We will create the same three connectivity MBeans and do some of the same management operations that we did through the browser interface.
The program listings in this tutorial show only functional code: comments and output statements have been modified or removed for space considerations. However, all management functionality has been retained for the various demonstrations. The complete source code is available in the BaseAgent and StandardMBean example directories located in the main examplesDir (see "Directories and Classpath" in the preface).
Contents:
"The Agent Application" shows how to launch the base agent programmatically.
"Creating an MBean (Method 1)" relies on the MBean server's register method after instantiating the MBean class ourselves.
"Creating an MBean (Method 2)" relies on the MBean server's create method to instantiate and register an MBean in one step.
"Creating an MBean (Method 3)" relies on the MBean server's instantiate and register methods.
"Managing MBeans" demonstrates the same management operations that we did through the HTML protocol adaptor.
"Filtering MBeans" shows how to get various lists of MBeans from the MBean server.
"Running the Base Agent Example" demonstrates its run-time behavior.
The base agent is a stand-alone application with a main method, but it also has a constructor so that it may be instantiated dynamically by another class.
public BaseAgent() { // Enable the TRACE level according to the level set in system properties try { Trace.parseTraceProperties(); } catch (IOException e) { e.printStackTrace(); System.exit(1); } echo("\n\tInstantiating the MBean server of this agent..."); myMBeanServer = MBeanServerFactory.createMBeanServer(); // Retrieves ID of the MBean server from the delegate try { System.out.println("ID = "+ myMBeanServer.getAttribute( new ObjectName(ServiceName.DELEGATE), "MBeanServerId")); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } |
In the first statement of the constructor, we enable tracing messages for the agent. The tracing lets us see internal information at runtime, which is useful for debugging. See "Setting Trace Messages" for specifying tracing parameters on the command line. Then we create the MBean server through its static factory class (see "The MBean Server Implementation and Factory"). Its reference is stored in a variable with class-wide scope so that all internal methods have access to the MBean server. Finally, we retrieve the MBean server identification string, for informational purposes only.
After the MBean server is initialized, we are going to create the same three communications MBeans that we saw in the minimal agent.
The methods of the MBean server let you create an MBean in three different ways. The base agent demonstrates all three ways, and we will discuss the advantages of each.
One way of creating an MBean consists of first instantiating its class and then registering this instance in the MBean server. Registration is the internal process of the MBean server which takes a manageable resource's MBean instance and exposes it for management.
Bold text in this and the following code samples highlights the important statements that vary between the three methods.
// instantiate the HTML protocol adaptor object to use the default port HtmlAdaptorServer htmlAdaptor = new HtmlAdaptorServer(); try { // We know that the HTML adaptor provides a default object name ObjectInstance htmlAdaptorInstance = myMBeanServer.registerMBean(htmlAdaptor, null); echo("CLASS NAME = " + htmlAdaptorInstance.getClassName()); echo("OBJECT NAME = " + htmlAdaptorInstance.getObjectName().toString()); } catch(Exception e) { e.printStackTrace(); System.exit(0); } // Now we need to explicitly start the html protocol adaptor htmlAdaptor.start(); while (htmlAdaptor.getState() == CommunicatorServer.STARTING) { sleep(1000); } echo("STATE = " + htmlAdaptor.getStateString()); [...] |
In this first case, we instantiate the HtmlAdaptorServer class and keep a reference to this object. We then pass it to the registerMBean method of the MBean server to make our instance manageable in the agent. During the registration, the instance can also obtain a reference to the MBean server, something it requires to function as a protocol adaptor.
In the minimal agent, we saw that the HTML adaptor gives itself a default name in the default domain. Its Javadoc API confirms this, so we can safely let it provide a default name. We print the object name in the object instance returned by the registration to confirm that the default was used.
Once the MBean is registered, we can perform management operations on it. Because we kept a reference to the instance, we don't need to go through the MBean server to manage this MBean. This lets us call the start and getStateString methods directly. The fact that these methods are publicly exposed is particular to the implementation: the HTML adaptor is a dynamic MBean, so without any prior knowledge of the class, we would have to go through its DynamicMBean interface.
In a standard MBean you would directly call the implementation of its management interface. Since the HTML adaptor is a dynamic MBean, the start method is just a shortcut for the start operation. For example, we could start the adaptor and get its StateString attribute with the following calls:
htmlAdaptor.invoke("start", new Object[0], new String[0]); echo("STATE = " + (String)htmlAdaptor.getAttribute("StateString"));
This type of shortcut is not specified by the Java Management extensions, nor is its functionality necessarily identical to that of the start operation exposed for management. In the case of the HTML adaptor, its Javadoc API confirms that it is identical, and in other cases, it is up to the MBean programmer to guarantee this functionality if it is offered.
The second way to create an MBean is the single createMBean method of the MBean server. In this case, the MBean server instantiates the class and registers it all at once. As a result, the caller never has a direct reference to the new object.
ObjectInstance httpConnectorInstance = null; try { String httpConnectorClassName = "com.sun.jdmk.comm.HttpConnectorServer"; // Let the HTTP connector server provides its default name httpConnectorInstance = myMBeanServer.createMBean(httpConnectorClassName, null); } catch(Exception e) { e.printStackTrace(); System.exit(0); } // We need the object name to refer to our MBean ObjectName httpConnectorName = httpConnectorInstance.getObjectName(); echo("CLASS NAME = " + httpConnectorInstance.getClassName()); echo("OBJECT NAME = " + httpConnectorName.toString()); // Now we demonstrate the bulk getter of the MBean server try { String att1 = "Protocol"; String att2 = "Port"; String attNames[]= {att1, att2}; AttributeList attList = myMBeanServer.getAttributes(httpConnectorName, attNames); Iterator attValues = attList.iterator(); echo("\t" + att1 + "\t=" + ((Attribute) attValues.next()).getValue()); echo("\t" + att2 + "\t=" + ((Attribute) attValues.next()).getValue()); } catch (Exception e) { e.printStackTrace(); System.exit(0); } // Now we explicitly start the HTTP connector server try { myMBeanServer.invoke(httpConnectorName, "start", new Object[0], new String[0]); // waiting to leave starting state... while (new Integer(CommunicatorServer.STARTING).equals (myMBeanServer.getAttribute(httpConnectorName,"State"))) { sleep(1000); } echo("STATE = " + myMBeanServer.getAttribute(httpConnectorName, "StateString")); } catch (Exception e) { e.printStackTrace(); System.exit(0); } [...] |
The advantage of this method for creating MBeans is that the instantiation and registration are done in one call. In addition, if we have registered any class loaders in the MBean server, they will automatically be used if the class is not available locally. See "The M-Let Class Loader" for more information on class loading.
The major difference is that we no longer have a reference to our MBean instance. The object instance that was only used for display purposes in the previous example now gives us the only reference we have on the MBean: its object name.
What can be seen as a drawback of this method is that all management of the new MBean must now be done through the MBean server. For the attributes of the MBean, we need to call the generic getter and setter of the MBean server, and for the operations we need to call the invoke method. When the agent needs to access the MBean, having to go through the MBean server adds some complexity to the code. It does have the advantage of not relying on any shortcuts provided by the MBean, making the code more portable and reusable.
However, the createMBean method is ideal for quickly launching new MBeans that the agent application doesn't need to manipulate. In just one call, the new objects are instantiated and exposed for management.
The last way of creating an MBean relies on the instantiate method of the MBean server. In addition, we use a non-default constructor to instantiate the class with a different behavior.
CommunicatorServer rmiConnector = null; Object[] params = {new Integer(8086)}; String[] signature = {new String("int")}; try { String RmiConnectorClassName = "com.sun.jdmk.comm.RmiConnectorServer"; // specify the RMI port number to use as a parameter to the constructor rmiConnector = (CommunicatorServer)myMBeanServer.instantiate( RmiConnectorClassName, params, signature); } catch(Exception e) { e.printStackTrace(); System.exit(0); } try { // Let the RMI connector server provides its default name ObjectInstance rmiConnectorInstance = myMBeanServer.registerMBean(rmiConnector, null); // Confirm the class and default object name echo("CLASS NAME = " + rmiConnectorInstance.getClassName()); echo("OBJECT NAME = " + rmiConnectorInstance.getObjectName().toString()); } catch(Exception e) { e.printStackTrace(); System.exit(0); } // Now we explicitly start the RMI connector server rmiConnector.start(); // waiting to leave starting state... while (rmiConnector.getState() == CommunicatorServer.STARTING) { sleep(1000); } echo("STATE = " + rmiConnector.getStateString()); // Check that the RMI connector server is started if (rmiConnector.getState() != CommunicatorServer.ONLINE) { echo("Cannot start the RMI connector server"); System.exit(0); } [...] |
As in the first example of MBean creation, we instantiate and register the MBean in separate steps. First, we instantiate the class using the instantiate method of the MBean server. This method lets you specify the constructor you wish to use when instantiating. Note that we could also have specified a constructor to the createMBean method in the previous example.
To specify a constructor, you give an array of objects for the parameters and an array of strings which defines the signature. If these arrays are empty or null, the MBean server will try to use the default no-parameter constructor. If the class does not have a public no-parameter constructor, you must specify the parameters and signature of a valid, public constructor.
In our case, we specify an integer parameter to set the port through one of the constructors of the RmiConnectorServer class. Then, we register the MBean with the registerMBean method of the MBean server, as in the first example.
The advantage of this creation method is that the instantiate method of the MBean server also supports class loaders. If any are registered in the MBean server, they will automatically be used if the class is not available locally. See "The M-Let Class Loader" for more information on class loading.
Since we don't take advantage of the class loaders here, we could have just called the class' constructor directly. The main advantage is that, like the first method of MBean creation, we retain a direct reference to the new object. The direct reference lets us again use the MBean's shortcut methods explicitly.
There are other combinations of instantiating and registering MBeans for achieving the same result. For example, we could use the default constructor and then set the port attribute of the MBean before starting it. Other combinations are left as an exercise to the reader.
In "Creating an MBean (Method 2)", we rely totally on the MBean server to create and access an MBean. The code example in that section demonstrates how to get attributes and invoke operations through the MBean server. Here we will concentrate on the usage of MBean descriptor classes when accessing MBeans representing resources.
We will rely on the StandardAgent and DynamicAgent classes presented in Instrumentation through MBeans. As mentioned in "Comparison with the SimpleStandard Example", the two are nearly identical. We examine the MBean descriptor method that is common to both: the same code works for any registered MBean, whether standard or dynamic.
private MBeanServer server = null; // assigned by MBeanServerFactory private void printMBeanInfo(ObjectName name) { echo("Getting the management information for " + name.toString() ); MBeanInfo info = null; try { info = server.getMBeanInfo(name); } catch (Exception e) { e.printStackTrace(); return; } echo("\nCLASSNAME: \t"+ info.getClassName()); echo("\nDESCRIPTION: \t"+ info.getDescription()); echo("\nATTRIBUTES"); MBeanAttributeInfo[] attrInfo = info.getAttributes(); if (attrInfo.length>0) { for(int i=0; i<attrInfo.length; i++) { echo(" ** NAME: \t"+ attrInfo[i].getName()); echo(" DESCR: \t"+ attrInfo[i].getDescription()); echo(" TYPE: \t"+ attrInfo[i].getType() + "\tREAD: "+ attrInfo[i].isReadable() + "\tWRITE: "+ attrInfo[i].isWritable()); } } else echo(" ** No attributes **"); echo("\nCONSTRUCTORS"); MBeanConstructorInfo[] constrInfo = info.getConstructors(); // Note: the class necessarily has at least one constructor for(int i=0; i<constrInfo.length; i++) { echo(" ** NAME: \t"+ constrInfo[i].getName()); echo(" DESCR: \t"+ constrInfo[i].getDescription()); echo(" PARAM: \t"+ constrInfo[i].getSignature().length + " parameter(s)"); } echo("\nOPERATIONS"); MBeanOperationInfo[] opInfo = info.getOperations(); if (opInfo.length>0) { for(int i=0; i<constrInfo.length; i++) { echo(" ** NAME: \t"+ opInfo[i].getName()); echo(" DESCR: \t"+ opInfo[i].getDescription()); echo(" PARAM: \t"+ opInfo[i].getSignature().length + " parameter(s)"); } } else echo(" ** No operations ** "); echo("\nNOTIFICATIONS"); MBeanNotificationInfo[] notifInfo = info.getNotifications(); if (notifInfo.length>0) { for(int i=0; i<constrInfo.length; i++) { echo(" ** NAME: \t"+ notifInfo[i].getName()); echo(" DESCR: \t"+ notifInfo[i].getDescription()); } } else echo(" ** No notifications **"); } |
The getMBeanInfo method of the MBean server gets the descriptor of an MBean's management interface and hides the MBean's implementation. This method returns an MBeanInfo object which contains the MBean's description. We can also get the lists of attributes, operations, constructors, and notifications to display their descriptions. Recall that the dynamic MBean provides its own meaningful descriptions and that those of the standard MBean are default strings provided by the introspection mechanism of the MBean server.
The base agent does very little filtering because it does very little management. Usually, filters are applied programmatically in order to get a list of MBeans to which some operations will apply. There are no management operations in the MBean server which apply to a list of MBeans: you must loop through your list and apply the desired operation to each MBean.
Before exiting the agent application, we do a query of all MBeans so that we can unregister them properly. MBeans should be unregistered before being destroyed since they may need to perform some actions before or after being unregistered.
public void removeAllMBeans() { try { Set allMBeans = myMBeanServer.queryNames(null, null); for (Iterator i = allMBeans.iterator(); i.hasNext();) { ObjectName name = (ObjectName) i.next(); // Don't unregister the MBean server delegate if ( ! name.toString().equals( ServiceName.DELEGATE ) ) { echo("Unregistering " + name.toString() ); myMBeanServer.unregisterMBean(name); } } } catch (Exception e) { e.printStackTrace(); System.exit(0); } } |
We use the queryNames method because we only need the object names to operate on MBeans. The null object name as a filter gives us all MBeans in the MBean server. We then iterate through the resulting set and unregister each one, except for the MBean server delegate. As described in "The MBean Server Delegate", the delegate is also an MBean and so it will be returned by the query. However, if we unregister it, the MBean server can no longer function and remove the rest of our MBeans.
We recognized the delegate by its standard name which is given by the static field ServiceName.DELEGATE. The ServiceName class provides standard names and other default properties for communications and service MBeans. It also provides the version strings that are exposed by the delegate MBean. Note that, since the delegate is the only MBean created directly by the MBean server, it is the only one whose name cannot be overridden during its registration. This is why the delegate always has the same object name, and we are always sure to detect it.
The examplesDir/BaseAgent/ directory contains the source file of the BaseAgent application. Compile the BaseAgent.java file in this directory with the javac command. For example, on the Solaris platform, you would type:
$ cd examplesDir/BaseAgent/ $ javac -classpath classpath *.java |
Again, we don't need the MBean classes at compile time, but they will be needed at run-time, since we don't use a dynamic class loader. You will need to have compiled the standard and dynamic MBean classes as described in "Running the Standard MBean Example" and "Running the Dynamic MBean Example". If you wish to load any other class in the base agent, you must include its directory or jar file in the classpath. To run the example, update your classpath to find the MBeans and launch the agent class:
$ java -classpath classpath:../StandardMBean:../DynamicMBean BaseAgent |
Since the base agent enables internal tracing (see Example 5-1), you can also set the trace level and trace output on the command line. The tracing mechanism is covered in the Java Dynamic Management Kit 4.1 Tools Reference guide and in the Javadoc API of the Trace class. The simplest way to get the default tracing is to specify the filename for a trace log on the java command line:
$ java -classpath classpath -DTRACE_OUTPUT=filename BaseAgent |
Besides any trace information, this agent displays output for the three types of MBean creation.
When the connection MBeans have been created, it is possible to connect to the agent through one of the protocols. The HTTP and RMI connector servers communicate with connector clients in manager applications, as will be done in some of the agent service example. If you connect to the base agent through the HTML adaptor, you could go through the same procedures as with the minimal agent.
When you are finished, type <Enter> to remove all MBeans from the agent and exit the agent application.