Version 11

    tracked by https://issues.jboss.org/browse/AS7-370

     

     

    The AS7 domain management does not currently provide notifications to let observers be notified when certain events of interest occurs.

    Use Cases

    Web console

    The Web console does not provide any notifications to users. The user is only informed of event that are the direct consequences of his actions.

    If someone else creates any resources, he will have to reload its browser page and make a mental note that there is a new resource compared to the previous display.

    In domain mode, the web console would be notified when a host join/leave the domain and refresh its display appropriately

     

    JMX Notification Replacement

    HornetQ (including in the messaging subsystem) sends JMX notifications upon some events (JMS resources created, consumers created for a given queue, security authorizarion violation, etc.)

    AS7 does not provide remote notifications and clients monitorigin these notifications must use the AS7 JMX facade to handle them.

     

    Out of scope

    No Metrics Notifications

    There is no notifications emitted by AS7 for resource metrics. It is up to clients interested to monitor these metrics to poll their values at regular interval.

    Requirements

    The Web Console uses the HTTP management API to manage AS7.

     

    Since the console runs in a Web browser, it could optionally leverage a push technology (WebSocket, Servert-sent Events) to let the server push the notifications to the browser.

    Other HTTP clients such a cURL have no access to such technology. A plain HTTP API must be available for these clients to be able to handle notifications.

     

    The Java management API needs to upgraded to be able to register/unregister notification handlers on the client-side.

     

    The clients may be interested to receive notifications for any resources of a given type (e.g. for all host resources or for all jms-queue resources). Since these resources can be created or removed dynamically, it is not the task of the client to track them down to update its list of resources to listen to. The notification API must accept address pattern to listen to all resources that matches this pattern.

     

    AS7 needs to define the notifications it emits. Some will be available globally (e.g. any resource will emit a notification when it is added or removed).

    However other notifications will be available only for some resources. A client must be able to query the resource description to find out the types of notifications emitted by any resource.

    Design

    AS7 resources describes their attributes, operations and children so that clients know how to interact with them.

    In a similar fashion, the AS7 resources describes the notifications it emits so that clients can decide whether they are interested to receive such notifications.

     

    Clients interact with AS7 resource notifications using the management API. The management API is extended to support notifications. The extensions are split in 4 parts:

     

    1. AS7 resource description now lists the notifications emitted by a resource (in addition to its attributes, operation and children)
    2. An service-based API internal to AS7 that can be used to register/unregister local notification handlers and let resources emit notifications
    3. A HTTP API to handle notifications from HTTP clients or web browsers
    4. A native Java API to handle notifications from remote Java clients

    Notification Description

    This section defines the notification description that complements the description of AS7 managed resources at https://docs.jboss.org/author/display/AS72/Description+of+the+Management+Model

     

    • notifications - Map of String (the notification type) to complex structure - the notifications that are emitted by the resource at this address.

     

    For example:

     

    {
        "description" => "A manageable resource",
        "attributes" => {
            ...
        },
        "operations" => {
           ...
        },
        "notifications" => {
            "foo" => { 
               ... details of the foo notification
           }
        },
        "children" => {
           ...
        }
    }
    

     

    A managed resource may define the notifications that it emits. The description of a notification will include the following information:

     

    • description - String - text description of the notification
    • data-type - ModelType or complex structure - only present if the notification will have a `data` value. data-type will detail the structure of the data value, enumerating the value's fields and the type of their value

     

    The read-resource-description operation that is available on all AS7 resources is extended to support the notifications. The new description below is updated with this information:

     

    The read-resource-description operation

    Returns the description of a resource's attributes, types of children and, optionally, operations and notifications. Supports the
    following parameters, none of which are required:

    • recursive – (boolean, default is false) – whether to include information about child resources, recursively.
    • proxies – (boolean, default is false) – whether to include remote resources in a recursive query (i.e. host level resources from slave Host Controllers in a query of the Domain Controller; running server resources in a query of a host)
    • operations – (boolean, default is false) – whether to include descriptions of the resource's operations
    • notifications – (boolean, default is false) – whether to include descriptions of the resource's notifications
    • inherited – (boolean, default is true) – if operations or notifications is true, whether to include descriptions of operations and notifications inherited from higher level resources. The global operations described in this section are themselves inherited from the root resource, so the primary effect of setting inherited to false is to exclude the descriptions of the global operations from the output. The notifications inherited by any resource are described in the following section.

     

    Global Notifications

     

    Any AS7 managed resource emits by default 3 types of notifications:

    • resource-added - when a resource is added, it emits a resource-added notification
    • resource-removed - when a resource is removed, it emits a resource-removed notification
    • attribute-value-written - when a write-attribute operation is performed successfully on a resource, it emits a attribute-value-written notification. The notification's `data` object contains the following information:
      • name - the name of the attribute
      • old-value - the previous value of the attribute
      • new-value - the new value of the attribute
      • storage - the storage type of the attribute (either "configuration" or "runtime")

     

    Internal Service-Based API

     

    NotificationSupport

    AS7 defines a NotificationSupport that can be used to:

    • register or unregister a NotificationHandler using the methods
      • registerNotificationHandler(PathAddress, NotificationHandler, NotificationFilter)
      • unregisterNotificationHandler(PathAddress, NotificationHandler, NotificationFilter)
    • emit a Notification
      • emit(Notification)

     

    The OperationContext implements the NotificationSupport interface so that any operation handlers can register/

    Any operation handlers can register/unregister handlers or emit notifications through the OperationContext.

     

    The notification support manages the registration of notification listeners and  keep their mapping to the resources emitting the notifications.

    There is no strong dependency between listeners and emitters. If an emitter resource is removed, this has no incidence on its listeners (except that they will handle no more notifications from this resource).

    The notification service will emit notifications (and call notification handlers) using the server thread pool if there is one and will not block the execution of the operation that triggered the notification.

     

    Resource's PathAddress Pattern

    When a notification handler is registered, it defines the PathAddress for the resource that will emit notifications.

    If a subsystem or extension is interested to listen to nofications for resources of the same type, it can use an address pattern to register once and have all resources matching this address send it notifications.

    An address pattern is an address whose at least one path element has a wildcard value (represented by *)

     

    For examples:

    • /subsystem=messaging/hornetq-server=default/jms-queue=* is an address pattern
    • /subsystem=messaging/hornetq-server=*/jms-queue=* is an address pattern
    • /subsystem=messaging/hornetq-server=default/jms-queue is NOT an address pattern

     

    For example, if the web console want to be notified when a host joins or leaves in domain mode, it needs to register a handler to the address /host=*.

    When a host (eg host-one) joins the domain, the handler will receive a resource-added notification for the resource at the address /host=host-one.

    Likewise, if a host (eg host-two) leaves the domain, the handler will receive a resource-removed notification for the resource at the address /host=host-two.

    NotificationHandler

    The handler must register to one or many AS7 resources' addresses.

    After registration, the handler receives a detyped representation of one (or many) notifications emitted by the resources.

    The handler can stop to receive notification by unregistering from the resources' addresses.

     

    The NotificationHandler is an interface that any subsystem or extension can implement to handle notifications. It defines a single method void: handleNotification(Notification).

    NotificationFilter

    When a notification handler is registered by the notification service, it must pass a NotificationFilter that will be checked to determine whether the handler will receive a notification or not.

    The NotificationFilter interface defines a single method: booelan isNotificationEnabled(Notification).

     

    Only notifications that returns true for the filter will be passed to the registered NotificationHandler

    Notification

    The Notification class represents data about the event of interest that triggered the notication emissions.

    The Notification class is used throughout the internal notification API. The remote API (both HTTP and Native Java) used a detyped representation of the notification to handle it.

     

    The detyped representation of a notification is a ModelNode composed of:

    • a mandatory `resource` LIST corresponding to the path address of the resource that emitted the notification (e.g. `/subsystem=messaging/hornetq-server=default/jms-queue=myQueue`). It represents the resource which has emitted the notification.
    • a mandatory `type` STRING which is an open-ended description of the notification type  (resource-added, resource-removed, attribute-value-changed, etc.). It corresponds to the type of notification as defined in the resource model description.
    • a mandatory `timestamp` LONG (from the Epoch in ms) corresponding to the date when the event that triggered the notification occurred.
    • a mandatory `message` STRING with a human-readable i18ned description of the event (e.g. "the attribute XXX value was changed to YYY")
    • an optional `data` OBJECT payload containing additional information contextual to the type of notification.

    HTTP API

    The HTTP API defines 2 differents ways to receive notifications:

    • a plain HTTP API that can be used from any HTTP clients
    • a Web browser-specific API that requires support of Server-sent events to receive notifications in the browser

     

    For a complete explanation of AS7 management API and its authentication requirements, please read https://docs.jboss.org/author/display/AS72/The+HTTP+management+API.

    The example below expect that an "admin" user has been created to manage AS7.

    Plain HTTP API

    Notification Handler Registration

    A handler can be registered to receive notification by sending a POST request to the /management/notification URL on the AS7 HTTP management server.

    The request body must be a JSON object containing a resources field with a list of all the resources' address to listen to.

     

    For example, a HTTP client wants to listen to 2 resources:

    • /subsystem=messaging/hornetq-server=default/
    • /subsystem=messaging/hornetq-server=*/jms-queue=* (note that this is an address pattern and will match any jms-queue resource)

     

    He can send the following HTTP request:

     

    $ curl --digest -L -D - http://localhost:9990/management/notification -u admin \
        --header "Content-Type: application/json" \
        -d '{"resources":[[{"subsystem":"messaging"}, {"hornetq-server":"default"}], [{"subsystem":"messaging"}, {"hornetq-server":"*"}, {"jms-queue":"*"}]]}'
    

     

    The server will reply with a 201 Created response. The response has a Location header corresponding to the URL of the handler resource that has just been created. It also has a Link header (with the relation notifications) corresponding to the handler's notifications resource.

     

    HTTP/1.1 201 Created
    Location: <handler_url>
    Link: <handler_notification_url>; rel=notifications
    

     

    The notification handler registration URL does not accept any other type of requests.

     

    Notification Handler Resource

    When the client send a GET request to the handler's URL, it retrieves a JSON object with the list of addresses that the handler is listening to. The response also contains the Link header for its notifications resource.

     

    $ curl -X GET --digest -u admin -L -D - http://localhost:9990/${handler_url}
    
    HTTP/1.1 200 OK
    Content-type: application/json
    Link: <handler_notification_url>; rel=notifications
    Date: Fri, 22 Feb 2013 15:08:01 GMT
    
    [[{ "subsystem" : "messaging" },{ "hornetq-server" : "default" }],[{ "subsystem" : "messaging" },{ "hornetq-server" : "default" },{ "jms-queue" : "*" }]]
    
    Update a handler

    A HTTP notification handler can listen to multiple AS7 resources. To update these addresses, the HTTP client can send a POST request to the handler URL with the updated list of addresses to listen to. This new list supersedes the existing list.

     

    For example, the client is no longer interested to receive notifications from /subsystem=messaging/hornetq-server=default/jms-queue=*. Instead he wants to listen to /subsystem=messaging/hornetq-server=default/jms-topic=*.

     

    $ curl --digest -L -D - http://localhost:9990/${handler_url} -u admin \
        --header "Content-Type: application/json" \
        -d '{"resources":[[{"subsystem":"messaging"}, {"hornetq-server":"default"}], [{"subsystem":"messaging"}, {"hornetq-server":"default"}, {"jms-topic":"*"}]]}'
    

     

    The server will send a 200 OK response if the handler has been correctly updated.

    Unregisted a handler

    To unregister a handler, send a DELETE request to its URL. The server will reply if a 204 No Content and the handler will no longer be available to receive notifications.

     

    $ curl -X DELETE --digest -u admin -L -D - http://localhost:9990/${handler_url}
    
    HTTP/1.1 204 No Content
    

    Notification Handler's Notifications Resource

     

    To retrieve the notifications that were received by the handlers, send a POST request to its handler's notifications URL (the  URL corresponding to the Link header with the relation notifications.

     

    The server will send a 200 OK response with either:

    • an empty body if no notifications were emitted since the last POST requests
    • a JSON object containing a list of notifications. The notifications are represented by the JSON conversion of their detyped management model.

     

    For example, let retrieve the notification of our registered handler:

     

    curl -X POST --digest -u admin -L -D - http://localhost:9990/${handler_notifications_url}
    
    HTTP/1.1 200 OK
    Content-type: application/json
    Content-length: 0
    

     

    No notifications were emitted and the client receives an empty body.

     

    Meanwhile, I change the value of the wildcard-routing-enable attribute of the default HornetQ server using the AS7 CLI console:

     

    [domain@localhost:9999 /] /subsystem=messaging/hornetq-server=default:write-attribute(name=wild-card-routing-enabled, value=true)
    {
        "outcome" => "success",
        "response-headers" => {
            "operation-requires-reload" => true,
            "process-state" => "reload-required"
        },
        "result" => {"outcome" => undefined}
    }
    

     

    If I fetch again the notification, this time I get one:

     

    curl -X POST --digest -u admin -L -D - http://localhost:9990/${handler_notifications_url}
    
    HTTP/1.1 200 OK
    Transfer-encoding: chunked
    Content-type: application/json
    
    [
      {
        "resource" : [
          {"subsystem" : "messaging" },
          {"hornetq-server" : "default" }
        ],
        "type" : "attribute-value-changed",
        "message" : "attribute wild-card-routing-enabled value written to true", 
        "timestamp" : 1361546539063,
        "data" : {
          "name" : "wild-card-routing-enabled",
          "old-value" : false,
          "new-value" : true,
          "storage" : "configuration"
        }
      }
    ]
    

     

    If the client try to fetch again, there are no more notifications that were emitted

     

    curl -X POST --digest -u admin -L -D - http://localhost:9990/${handler_notifications_url}
    
    HTTP/1.1 200 OK
    Content-type: application/json
    Content-length: 0
    

     

    The handler's notifications resource accepts no other methods than POST.

     

    One each POST request, the client will receive the N most recent notifications that were emitted since its last POST request. Once the POST response is sent, the server will flush the notifications held for this client. He will not receive twice the same notification.

    It is possible to miss notifications if the client does not poll often enough and there are more than N notifications emitted. This is a compromise to prevent exhausting server memory by having clients register a listener and never poll its notifications that'll fill up the memory.

    Having a sensible value for N (e.g. 1024) should leave enough time for a client to poll regularly and not miss most notifications.

    HTML5 Server-sent Events API

    The HTTP API provides a Web browser-specific way to receive notifications that requires the support of HTML5 Server-sent Events.

     

    If the web browser supports it, it can register against the AS7 HTTP API to be notified by pushing notifications to the browser.

     

    The JavaScript snippet below shows how to register the web browser to receive notifications for any jms-queue resource.

     

    var source = new EventSource('/notification/sse?address=/subsystem%3Dmessaging/hornetq-server%3D*&address=/subsystem%3Dmessaging/hornetq-server%3D*/jms-queue%3D*')
    source.onmessage=function(event) {
      var notification = JSON.parse(event.data);
      // the notification is an object that corresponds to the detyped representation of a Notification object
      ...
    }
    

     

    The Server-sent event endpoint URL is /notification/sse. To define which resources to listen to, pass one (or many) address query parameter with a URL-encoded representation of the resource's path (similar to the path used by the AS7 cli console).

     

    For example, to handle notifications from the resources /subsystem=messaging/hornetq-server=*/jms-queue=* (i.e. all jms-queue resources), the corresponding query parameter is:

     

    address=/subsystem%3Dmessaging/hornetq-server%3D*&address=/subsystem%3Dmessaging/hornetq-server%3D*/jms-queue%3D*
    

     

    After the registration is successful, for each emitted notification, the EventSource's onmessage callback function will be called with the String representation of the notification. Use JSON.parse to obtain a JSON representation of the notification.

     

    Native Management Java API

    Remote Java clients can listen notifications emitted by AS7 resource using its native management API.


    The ModelControllerClient defines 2 methods to unregister/unregister notification handlers:

     

    void registerNotificationHandler(ModelNode resourceAddress, NotificationClientHandler handler, NotificationClientFilter filter);
    
    
    void unregisterNotificationHandler(ModelNode resourceAddress, NotificationClientHandler handler, NotificationClientFilter filter);
    
    

     

    The resourceAddress correspond to the detyped representation of a AS7 resource's PathAddress.

     

    The only data that goes over the wire for the notifications API are:

    • the resourceAddress ModelNode
    • the notification ModelNode