/** *

Defines the Event Service, which provides extended support * for JMX notifications.

* *

The Event Service provides greater control over * notification handling than the default technique using {@link * javax.management.MBeanServer#addNotificationListener(ObjectName, * NotificationListener, NotificationFilter, Object) * MBeanServer.addNotificationListener} or {@link * javax.management.MBeanServerConnection#addNotificationListener(ObjectName, * NotificationListener, NotificationFilter, Object) * MBeanServerConnection.addNotificationListener}.

* *

Here are some reasons you may want to use the Event Service:

* * * *

The Event Service is new in version 2.0 of the JMX API, which is the * version introduced in version 7 of the Java SE platform. It is not usually * possible to use the Event Service when connecting remotely to an * MBean Server that is running an earlier version.

* * *

Handling remote notifications with the Event * Service

* *

Prior to version 2.0 of the JMX API, every connector * had to include logic to handle notifications. The standard {@linkplain * javax.management.remote.rmi RMI} and JMXMP connectors defined by JSR 160 handle notifications * in a way that is not always appropriate for applications. Specifically, * the connector server adds one listener to every MBean that might emit * notifications, and adds all received notifications to a fixed-size * buffer. This means that if there are very many notifications, a * remote client may miss some, even if it is only registered for a * very small subset of notifications. Furthermore, since every {@link * javax.management.NotificationBroadcaster NotificationBroadcaster} MBean * gets a listener from the connector server, MBeans cannot usefully optimize * by only sending notifications when there is a listener. Finally, since * the connector server uses just one listener per MBean, MBeans cannot * impose custom behavior per listener, such as security checks or localized * notifications.

* *

The Event Service does not have these restrictions. The RMI connector * that is included in this version of the JMX API uses the Event Service by * default, although it can be configured to have the previous behavior if * required.

* *

The Event Service can be used with any connector via the * method {@link javax.management.event.EventClient#getEventClientConnection * EventClient.getEventClientConnection}, like this:

* *
 * JMXConnector conn = ...;
 * MBeanServerConnection mbsc = conn.getMBeanServerConnection();
 * MBeanServerConnection eventMbsc = EventClient.getEventClientConnection(mbsc);
 * 
* *

If you add listeners using {@code eventMbsc.addNotificationListener} * instead of {@code mbsc.addNotificationListener}, then they will be handled * by the Event Service rather than by the connector's notification system.

* *

For the Event Service to work, either the {@link * javax.management.event.EventClientDelegateMBean EventClientDelegateMBean} * must be registered in the MBean Server, or the connector server must * be configured to simulate the existence of this MBean, for example * using {@link javax.management.event.EventClientDelegate#newForwarder() * EventClientDelegate.newForwarder()}. The standard RMI connector is so * configured by default. The {@code EventClientDelegateMBean} documentation * has further details.

* * *

Receiving notifications from a set of MBeans

* *

The Event Server allows you to receive notifications from every MBean * that matches an {@link javax.management.ObjectName ObjectName} pattern. * For local clients (in the same JVM as the MBean Server), the {@link * javax.management.event.EventSubscriber EventSubscriber} class can be used for * this. For remote clients, or if the same code is to be used locally and * remotely, use an * {@link javax.management.event.EventClient EventClient}.

* *

EventSubscriber and EventClient correctly handle the case where a new * MBean is registered under a name that matches the pattern. Notifications * from the new MBean will also be received.

* *

Here is how to receive notifications from all MBeans in a local * {@code MBeanServer} that match {@code com.example.config:type=Cache,*}:

* *
 * MBeanServer mbs = ...;
 * NotificationListener listener = ...;
 * ObjectName pattern = new ObjectName("com.example.config:type=Cache,*");
 * EventSubscriber esub = EventSubscriber.getEventSubscriber(mbs);
 * esub.{@link javax.management.event.EventSubscriber#subscribe
 * subscribe}(pattern, listener, null, null);
 * 
* *

Here is how to do the same thing remotely:

* *
 * MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();
 * EventClient events = new EventClient(mbsc);
 * NotificationListener listener = ...;
 * ObjectName pattern = new ObjectName("com.example.config:type=Cache,*");
 * events.{@link javax.management.event.EventClient#subscribe
 * subscribe}(pattern, listener, null, null);
 * 
* * *

Controlling threading behavior for notification * dispatch

* *

The EventClient class can be used to control threading of listener * dispatch. For example, to arrange for all listeners to be invoked * in the same thread, you can create an {@code EventClient} like this:

* *
 * MBeanServerConnection mbsc = ...;
 * Executor singleThreadExecutor = {@link
 * java.util.concurrent.Executors#newSingleThreadExecutor()
 * Executors.newSingleThreadExecutor}();
 * EventClient events = new EventClient(
 *         mbsc, null, singleThreadExecutor, EventClient.DEFAULT_LEASE_TIMEOUT);
 * events.addNotificationListener(...);
 * events.subscribe(...);
 * 
* * *

Leasing

* *

The {@code EventClient} uses a lease mechanism to ensure * that resources are eventually released on the server even if the client * does not explicitly clean up. (This can happen through network * partitioning, for example.)

* *

When an {@code EventClient} registers with the {@code * EventClientDelegateMBean} using one of the {@code addClient} methods, * an initial lease is created with a default expiry time. The {@code * EventClient} requests an explicit lease shortly after that, with a * configurable expiry time. Then the {@code EventClient} periodically * renews the lease before it expires, typically about half way * through the lifetime of the lease. If at any point the lease reaches * the expiry time of the last renewal then it expires, and {@code * EventClient} is unregistered as if it had called the {@link * javax.management.event.EventClientDelegateMBean#removeClient removeClient} * method.

* * *

Custom notification transports

* *

When you create an {@code EventClient}, you can define the transport * that it uses to deliver notifications. The transport might use the * Java Message Service (JMS) or * any other communication system. Specifying a transport is useful for * example when you want different network behavior from the default, or * different reliability guarantees. The default transport calls {@link * javax.management.event.EventClientDelegateMBean#fetchNotifications * EventClientDelegateMBean.fetchNotifications} repeatedly, which usually means * that there must be a network connection permanently open between the client * and the server. If the same client is connected to many servers this can * cause scalability problems. If notifications are relatively rare, then * JMS or the {@linkplain javax.management.event.RMIPushEventRelay push-mode * RMI transport} may be more suitable.

* *

A transport is implemented by an {@link javax.management.event.EventRelay * EventRelay} on the client side and a corresponding {@link * javax.management.event.EventForwarder EventForwarder} * on the server side. An example is the {@link * javax.management.event.RMIPushEventRelay RMIPushEventRelay} and its * {@link javax.management.event.RMIPushEventForwarder RMIPushEventForwarder}.

* *

To use a given transport with an {@code EventClient}, you first create * an instance of its {@code EventRelay}. Typically the {@code EventRelay}'s * constructor will have a parameter of type {@code MBeanServerConnection} * or {@code EventClientDelegateMBean}, so that it can communicate with the * {@code EventClientDelegateMBean} in the server. For example, the {@link * javax.management.event.RMIPushEventForwarder RMIPushEventForwarder}'s constructors * all take an {@code EventClientDelegateMBean} parameter, which is expected to * be a {@linkplain javax.management.JMX#newMBeanProxy(MBeanServerConnection, * ObjectName, Class) proxy} for the {@code EventClientDelegateMBean} in the * server.

* *

When it is created, the {@code EventRelay} will call * {@link javax.management.event.EventClientDelegateMBean#addClient(String, * Object[], String[]) EventClientDelegateMBean.addClient}. It passes the * name of the {@code EventForwarder} class and its constructor parameters. * The {@code EventClientDelegateMBean} will instantiate this class using * {@link javax.management.MBeanServer#instantiate(String, Object[], String[]) * MBeanServer.instantiate}, and it will return a unique client id.

* *

Then you pass the newly-created {@code EventRelay} to one of the {@code * EventClient} constructors, and you have an {@code EventClient} that uses the * chosen transport.

* *

For example, when you create an {@code RMIPushEventRelay}, it * uses {@code MBeanServerDelegateMBean.addClient} to create an {@code * RMIEventForwarder} in the server. Notifications will then be delivered * through an RMI communication from the {@code RMIEventForwarder} to the * {@code RMIPushEventRelay}.

* * *

Writing a custom transport

* *

To write a custom transport, you need to understand the sequence * of events when an {@code EventRelay} and its corresponding {@code * EventForwarder} are created, and when a notification is sent from the {@code * EventForwarder} to the {@code EventRelay}.

* *

When an {@code EventRelay} is created:

* * * *

When an {@code EventClient} is created with an {@code EventRelay} * parameter, it calls {@link javax.management.event.EventRelay#setEventReceiver * EventRelay.setEventReceiver} with an {@code EventReceiver} that the * {@code EventRelay} will use to deliver notifications.

* *

When a listener is added using the {@code EventClient}, the * {@code EventRelay} and {@code EventForwarder} are not involved.

* *

When an MBean emits a notification and a listener has been added * to that MBean using the {@code EventClient}:

* * * *

When the {@code EventClient} is closed ({@link * javax.management.event.EventClient#close EventClient.close}):

* * * * *

Threading and buffering

* *

The {@link javax.management.event.EventForwarder#forward * EventForwarder.forward} method may be called in the thread that the * source MBean is using to send its notification. MBeans can expect * that notification sending does not block. Therefore a {@code forward} * method will typically add the notification to a queue, with a separate * thread that takes notifications off the queue and sends them.

* *

An {@code EventRelay} does not usually need to buffer notifications * before giving them to * {@link javax.management.event.EventReceiver#receive EventReceiver.receive}. * Although by default each such notification will be sent to potentially-slow * listeners, if this is a problem then an {@code Executor} can be given to * the {@code EventClient} constructor to cause the listeners to be called * in a different thread.

* * @since 1.7 */ package javax.management.event;