Version 20

    JBoss Messaging Configuration and Management

     

    This document provides the base for a discussion on Messaging configuration and management facilities. Please post your comments on this forum http://www.jboss.org/index.html?module=bb&op=viewtopic&t=74846.

     

    Overview of JBossMQ Configuration Facilities

     

    A JBossMQ instance is an aggregation of inter-dependent MBeans whose start-up configuration is specified as attributes of <mbean> elements. A map of component MBeans, corresponding configuration files and configuration/management attributes.

     

     

    Proposed Messaging Configuration and Management Facilities

     

    Remoting

    The JBossMQ InvocationLayer MBeans and their corresponding configuration files (uil2-service.xml, jvm-il-service.xml, etc.) are rendered irrelevant and replaced by Remoting configuration files.

     

    Each Messaging server peer relies on a Remoting Connector instance. The connector's associated invokers receive and forward local and remote invocations to a JMSServerInvocationHandler installed by the server peer. Both the Remoting connector and the server peer have been written to be totally independent from each other, in that a server peer can use an arbitrary connector and a connector can forward invocation to an arbitrary number of server peers, provided that each peer uses a different remoting subsystem tag.

     

    A JBoss 5.0 instance declares a singleton Connector in its main configuration file and by default, the server peer will use this default connector instance and its default configuration. At service start up time, the server peer will register its invocation handler (a JMSServerInvocationHandler instance) so it needs the connector's ObjectName, which will get via a <depends> element that also insures the connector is started. The Messaging server peer MBean may also exposes a convenience read-only managed attribute that returns the value of the connector's locator.

     

    TODO: Provide a HTTP invoker configuration.

     

    Client-side and server-side interceptor chains

     

    The JBossMQ interceptors are replaced by standard AOP interceptors and aspects. The interceptors are not deployed as MBeans anymore so they are not configured via service deployment descriptors. The server instance advises dynamically at runtime client-side delegate classes and server-side endpoint classes, based on two AOP configuration files: aop-messaging-client.xml and aop-messaging-server.xml. Examples are provided below:

     

     

    aop-messaging-server.xml:

     

            <?xml version="1.0" encoding="UTF-8"?>
            <!DOCTYPE aop PUBLIC
               "-//JBoss//DTD JBOSS AOP 1.0//EN"
               "http://www.jboss.org/aop/dtd/jboss-aop_1_0.dtd">
            <aop>
    
               <interceptor class="org.jboss.jms.server.container.LogInterceptor" scope="PER_VM"></interceptor> 
               <interceptor class="org.jboss.jms.server.container.CachingInterceptor" scope="PER_VM"></interceptor>    
               <aspect class="org.jboss.jms.server.container.SecurityAspect" scope="PER_VM"></aspect>
               <aspect class="org.jboss.jms.server.container.InjectionAspect" scope="PER_VM"></aspect>
    
               <!-- Connection -->
               <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.ConnectionAdvised->
                     $implementing{org.jboss.jms.server.endpoint.ConnectionEndpoint}(..))">
                  <interceptor-ref name="org.jboss.jms.server.container.LogInterceptor"></interceptor-ref>
               </bind>
    
               <!-- Session -->
               <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.SessionAdvised->
                     $implementing{org.jboss.jms.server.endpoint.SessionEndpoint}(..))">
                  <interceptor-ref name="org.jboss.jms.server.container.LogInterceptor"></interceptor-ref>
               </bind>
               <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.SessionAdvised->
                     createProducerDelegate(..))">
                  <advice name="handleCreateProducerDelegate" 
                          aspect="org.jboss.jms.server.container.SecurityAspect"></advice>
               </bind>
               <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.SessionAdvised->
                     createBrowserDelegate(..))">
                  <advice name="handleCreateBrowserDelegate" 
                          aspect="org.jboss.jms.server.container.SecurityAspect"></advice>
               </bind>
               <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.SessionAdvised->
                     createConsumerDelegate(..))">
                  <advice name="handleCreateConsumerDelegate" 
                          aspect="org.jboss.jms.server.container.SecurityAspect"></advice>
               </bind> 
               <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.SessionAdvised->
                     createConsumerDelegate(..))">
                  <advice name="handleCreateConsumerDelegate" 
                          aspect="org.jboss.jms.server.container.InjectionAspect"></advice>
               </bind>
    
               <!-- Producer -->
               <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.ProducerAdvised->
                     $implementing{org.jboss.jms.server.endpoint.ProducerEndpoint}(..))">
                  <interceptor-ref name="org.jboss.jms.server.container.LogInterceptor"></interceptor-ref>  
               </bind>
               <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.ProducerAdvised->
                     send(..))">
                  <advice name="handleSend" aspect="org.jboss.jms.server.container.SecurityAspect"></advice>
               </bind>
    
               <!-- Consumer -->
               <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.ConsumerAdvised->
                     $implementing{org.jboss.jms.server.endpoint.ConsumerEndpoint}(..))">
                  <interceptor-ref name="org.jboss.jms.server.container.LogInterceptor"></interceptor-ref>  
               </bind>
    
               <!-- Browser -->
               <bind pointcut="execution(* org.jboss.jms.server.endpoint.advised.BrowserAdvised->
                     $implementing{org.jboss.jms.server.endpoint.BrowserEndpoint}(..))">
                  <interceptor-ref name="org.jboss.jms.server.container.LogInterceptor"></interceptor-ref>  
               </bind>
             
            </aop>
    

     

    The AOP configuration is loaded as resource during the service startup, so they must be in the deployment's UCL classpath.

     

    TODO: Adding a custom client-side or server-side interceptor involves modifying one of these files. Even if they are conceptually straightforward, they look daunting and difficult to change without tool support, so we need to provide examples of how to write and configure a new client-side or server-side interceptor.

     

    Server Peer

    The ServerPeer instance is the hub into which various components plug in at startup. Currently, the server peer maintains direct references to

     

    • DestinationManager - manages destination maps

    • ClientManager - manages the active connection endpoint map

    • SecurityManager - stores per-destination security configuration and maintains direct references to the AuthenticationManager and RealMapping delegates

    • TransactionRepository - manages local JMS transactions

    • * JMSServerInvocationHandler* - receives invocations from Remoting and forwards them to the server

    • PersistenceManager (the future TransactionLogDelegate/LazyDelegate, http://www.jboss.org/index.html?module=bb&op=viewtopic&t=73650 and http://www.jboss.org/index.html?module=bb&op=viewtopic&t=73137) - O/R mapper. Must be pluggable and each implementation may have its own arbitrary configuration.

    • MessageStore - references/dereferences messages. Must be pluggable and each implementation may have its own arbitrary configuration.

    • StateManager - manages the durable subscription map. Must be pluggable and each implementation may have its own arbitrary configuration.

    • ThreadPool - manages threads used to deliver messages to consumers. Must be pluggable and each implementation may have its own arbitrary configuration.

     

     

    Currently DestinationManager and StateManager are registered as MBeans with the MBeanServer during the server startup.

     

    In my opinion DestinationManager, ClientManager, SecurityManager, TransactionRepository and JMSServerInvocationHandler must not be declared as independent services (MBeans), nor registered with the MBeanServer. There is no reason for that, as they will never be independently re-deployed or have dependencies on their own. MBeans are useful to achieve decoupling, but these service do not need to be decoupled. They form a larger functional unit, under ServerPeer's umbrella.

     

    This is an initial matrix of per-component JMX features that should migrate to ServerPeer management interface:

     

    Component

    Read-only attributes

    Write-only attributes

    Read-write attributes

    Managed Operations

    DestinationManager

    Destination-related statistics (queue count, topic count, etc)

    TBD

    Destination default parameters (maximum depth, redelivery delay, redelivery limit, recovery retries, expiry destination, etc)

    dump destination map (text, XML), TBD

    ClientManager

    Connection-related statistics (client count, etc)

    TBD

    TBD

    dump clients (text, XML)

    SecurityManager

    TBD

    TBD

    Destination default security attributes (a list of roles and their associated permisions)

    TBD

    TransactionRepository

    TBD

    TBD

    TBD

    dump active transaction list

    JMSServerInvocationHandler

    None

    None

    None

    None

    ServerPeer

    JMS Version

    Server Version

    InvokerLocator

    TBD

    serverPeerID

    Connector ObjectName

    PersistenceManager ObjectName

    MessageStore ObjectName

    StateManager ObjectName

    ThreadPool ObjectName

    TBD

     

     

    PersistenceManager, MessageStore, StateManager and ThreadPool's implementations must be pluggable. Since it is reasonable to assume that various implementations will require different configuration attributes, the best way to deploy the plugins is as services, so they automatically expose their custom management interface. The server peer should, however, get direct references to these services through their management interface (getInstance()) and invoke contract methods directly on the instance. No need for dynamic proxies, since we don't plan on hot-redeploying a PersistenceManager or ThreadPool (or do we?)

     

    These services should be implemented as XMBeans.

     

    As a general rule, for each service configuration parameter should be clarified whether it makes sense to be changed at runtime. If only makes sense for that parameter to be set up at start up time, then the service constructor should provide for it, and the correspoinding manangement attribute should be read-only. If it makes sense to be changed at run-time, then it should be present in the constructor and it should also have a read-write managed attribute.

     

     

     

    Configuration parameters/management interfaces:

     

    ThreadPool

     

    Contract (mostly irrelevant for the configuration discussion, but interesting nonetheless):

     

         TODO
    

     

    Management interface:

     

    Component

    Read-only attributes

    Constructor arguments (also exposed as read-only attributes)

    Write-only attributes

    Read-write attributes

    Managed Operations

    ThreadPool

    Instance

    PoolSize (active thread count)

    etc.

    None

    None

    MaxPoolSize

    MinPoolSize

    KeepAliveTime etc.

    TBD

     

    This partial list of managed atribute had been compiled based on the concurrent's PooledExecutor implementation. JBossMQ has its own implementation of a thread pool that comes with its own configuration parameters (MinimumPoolSize, MaximumPoolSize, QueueSize, MaximumQueueSize, BlockingMode, ThreadGroupName, KeepAliveTime). Just these two examples should be sufficient to demonstrate the usefulness of deploying the thread pool as separate MBeans: an XMBean's (or a simple StandardMBean's) management interface is generated dynamically so it won't be necessary to modify ServerPeer's management interface to accomodate a new ThreadPool implementation.

     

    Again, the fact that an arbitrary ThreadPool implementation is deployed as a service doesn't mean the ThreadPool will be hot redeployable, nor does it need to be. The effects of a thread pool hot redeployment on the messaging core are hard to predict and no such feature is necessary. The ServerPeer will get a hard reference to the ThreadPool during its start() sequence, and that would be all.

     

    PersistenceManager

     

    TBD

     

    MessageStore

     

    TBD

     

    StateManager

     

    TBD

     

    Putting together all these, this is how a messaging-server.xml file should look like

     

    <server>
    
       <mbean code="org.jboss.jms.server.ServerPeer" name="jboss.messaging:service=ServerPeer"
              xmbean-dd="xmdesc/ServerPeer-xmbean.xml">
    
          <depends optional-attribute-name="Connector">jboss.remoting:service=Connector,transport=socket</depends>    
          <depends optional-attribute-name="PersistenceManager">jboss.messaging:service=PersistenceManager</depends>
          <depends optional-attribute-name="MessageStore">jboss.messaging:service=MessageStore</depends>
          <depends optional-attribute-name="StateManager">jboss.messaging:service=StateManager</depends>
          <depends optional-attribute-name="ThreadPool">jboss.messaging:service=ThreadPool</depends>
          <depends>jboss:service=TransactionManager</depends>
    
          <attribute name="ID">peer0</attribute>
          <attribute name="DefaultDestinationConfig">
            <destination>              
                <maximum-depth>-1</maximum-depth>
                <redelivery-delay>500</redelivery-delay>
                <redelivery-limit>10</redelivery-limit>
                <recovery-retries>10</recovery-retries>
            </destination>
          </attribute>
          <attribute name="SecurityDomain">java:/jaas/messaging</attribute>
          <attribute name="DefaultSecurityConfig">
            <security>              
                <role name="guest" read="true" write="true" create="true"></role>
            </security>
          </attribute>
       </mbean>
     
    
       <!-- Persistence Manager -->
       <mbean code="org.jboss.jms.server.plugins.SomePersistenceManager" 
              name="jboss.messaging:type=plugin,service=PersistenceManager"
              xmbean-dd="xmdesc/PersistenceManager-xmbean.xml">
    
          <depends optional-attribute-name="ConnectionManager">
              jboss.jca:service=DataSourceBinding,name=DefaultDS</depends>
         
          <!-- implementation-specific attributes -->
          .....
       </mbean>
    
    
       <!-- Message Store -->
       <mbean code="org.jboss.jms.server.plugins.SomeMessageStoreImplementation" 
              name="jboss.messaging:type=plugin,service=MessageStore"
              xmbean-dd="xmdesc/MessageStore-xmbean.xml">
    
          <depends optional-attribute-name="ConnectionManager">
              jboss.jca:service=DataSourceBinding,name=DefaultDS</depends>
         
          <!-- implementation-specific attributes -->
          .....
       </mbean>
    
     
       <!-- State Manager -->
       <mbean code="org.jboss.jms.server.plugins.SomeStateManagerImplementation" 
              name="jboss.messaging:type=plugin,service=StateManager"
              xmbean-dd="xmdesc/StateManager-xmbean.xml">
    
          <depends optional-attribute-name="ConnectionManager">
              jboss.jca:service=DataSourceBinding,name=DefaultDS</depends>
         
          <!-- implementation-specific attributes -->
          .....
       </mbean>
    
    
       <!-- Thread Pool -->
       <mbean code="...." name="jboss.messaging:type=plugin,service=ThreadPool">
          <!-- implementation-specific attributes -->
          .....
       </mbean>
    
    
       <!-- DLQ -->
       <mbean code="org.jboss.jms.server.jmx.Queue" 
              name="jboss.messaging.destination:service=Queue,name=DLQ"></mbean>
    
       <!-- Other destinations  -->
    </server>
    

     

    Client-side Configuration

     

    First of all, the "Client-side Configuration" title could be misleading and needs a clarification. This paragraph describes the configurable parameters of the client-side JMS facade. However, the files that contain initial values for these parameters are located on the server-side, and JMS client code must do nothing and should not attempt to access these file or get/set configuration. All JMS client code need to do is to lookup a connection factory in JNDI and use it to create a connection. The client-side configurable parameters will be embedded in the connection factory instance or will be transparently get by the client-side JMS facade in conversation with the server.

     

     

    Configurable client-side JMS facade parameters:

     

    • Connection/Session/MessageProducer/MessageConsumer/QueueBrowser's aspect chain

    • ConnectionState's thread pool implementing class and custom parameters

    • SessionState's thread pool implementing class and custom parameters (TODO: do we really need so many  thread pools (n + 1)?)

    • etc

     

    The aspect configuration chains and the associated pointcuts are specified in aop-messaging-server.xml on the server side.  This configuration file is loaded by the server peer as resource during the service startup, so it must be in the deployment's UCL classpath. Upon connection creation, the client-side AOP configuration is transferred as byte array on the client, where it is loaded by a custom aspect loader.

     

    An example of aop-messaging-client.xml is available here.

     

     

    All other client-side configuration parameters should be all specified in the deployment descriptor of the ConnectionFactory that was used to create the connection. There are cases when an aspect initialization value can be specified both in the aop.xml file and the connection factory deployment descriptor. Example: the number of messages to buffer in a BrowserInterceptor. Both ways to configure the value are valid, and the value specified in the connection factory deployment descriptor takes precedence.

     

     

    Connection Factories

     

    A connection factory is deployed as an MBean. The MBean's deployment descriptor should contain:

    • The connection factory JNDI name.

    • The remoting protocol to use (provided that more than one protocol is made available by the connector)

    • Custom client configuration (see above).

     

    Destinations

     

    They don't vastly differ from JBossMQ destinations. Some adjustments to map to the current implementation may be needed, but the general structure stays the same.

     

    Destinations may be created either administratively as a result of a service deployment or programmatically, by invoking managed operations on server peer.

     

    Deployed Destinations

     

    During deployment, a Destination service will need to make calls into the ServerPeer instance to make itself noticed and then registered by the server. The registration will result in creation of server-managed destination state (a core channel instance plus additional state).

     

    A Destination service interacts with the server peer via server's DestinationManager interface. A Destination service instance sends invocations into the server either via a typed dynamic proxy or via a typed hard reference (preferred, since I don't envision hot redeployment of the server peer relative to its deployed destinations).

     

    The DestinationManager interface must not be exposed as part of the management interface. This is not for public consumption by a JMX Client.

       DestinationManager
       {
          registerDestination(...)
          unregisterDestination(...)
       }
    

     

    However, a destination may be hot redeployed relative to its server peer, so the server peer will send JMX invocations into its destination services (total decoupling)

     

    TODO: Unit test for a destination hot re-deployment.

     

    Dynamically Created Destinations

     

    The user must be able to create destination using the Server's JMX interface (interactively using a JMX management client, or programmatically, via a JMX calls).

     

    Destination management methods:

     

         createDestination(...)
    

     

     

    No destroyDestination() is necessary. A newly created destination can be further managed (including shutting it down) via its own JMX management interface, now that the destination is a service on its own.

     

    Such a destination creation must end in a new Destination service being deployed (?), so the user may continue to interact with the new created destination no differently than with a destination that was deployed the usual way.

     

    It would be good if the programmatically created destinations could save their state and survive a server restart.

     

     

    Clustering

     

    TODO