JBoss Community

Currently Being Moderated

AS5ServiceBindingManager

VERSION 19

Created on: Aug 2, 2008 7:25 PM by Brian Stansberry - Last Modified:  Jun 2, 2009 4:08 PM by Brian Stansberry

Searchable Title: Service Binding Manager in JBoss Application Server 5

 

Overview of Changes

 

As in previous JBoss AS releases, the AS 5.0.0.CR2 and later Service Binding Manager service provides a centralized location where settings for all services that need to bind to ports can be configured.  As in previous releases, different named sets of bindings can be configured, with a property on the Service Binding Manager service itself controlling which named set (e.g. ports-default or ports-01) a particular AS instance uses. Different AS instances use different binding sets. In a typical configuration, the ports-default set uses the standard ports discussed in the AS documentation (e.g. JNDI on port 1099), with ports-01 increasing each port value by 100 (e.g. JNDI on 1199), ports-02 by 200, etc.

 

Similarly to earlier releases, the standard way to configure the named sets of bindings is via XML, although in AS 5 the XML format is considerably different, relying on a standard JBoss Microcontainer -jboss-beans.xml format, rather than the custom DTD used in earlier releases.

 

The fundamental difference from earlier releases is in how the bindings are applied. In earlier releases, the Service Binding Manager service was an optional service that, if enabled, would check all mbean deployments in the middle of the deployment process and attempt to override the configuration of the mbean with values from its own configuration.  In AS 5, services that need to know about port bindings don't have default configurations that get overridden; instead the initial configuration of those services delegates to the Service Binding Manager service to get the proper values. Service Binding Manager functions as a "factory" for configuration values.

 

I'll use the configuration of the dynamic class and resource loading service (aka jboss:service=WebService) to illustrate the essential differences.

 

Basic Service Binding in JBoss 4.x

 

In earlier releases, the default binding for a service would be declared in the standard configuration file for that service, e.g. the following from conf/jboss-service.xml:

 

<!-- A mini webserver used for dynamic and class and resource loading -->
<mbean code="org.jboss.web.WebService" name="jboss:service=WebService">
   ...
   <attribute name="Port">8083</attribute>
   ...
</mbean>

 

To get replacement of that port 8083 binding to work, a user would then have to uncomment the jboss.system:service=ServiceBindingManager mbean in conf/jboss-service.xml, identify where to find the config file for the service is located (or accept the default) and specify what set of bindings to use via the ServerName attribute.

 

<mbean code="org.jboss.services.binding.ServiceBindingManager" 
          name="jboss.system:service=ServiceBindingManager">
  <attribute name="ServerName">ports-01</attribute>
  <attribute name="StoreURL">../docs/examples/binding-manager/sample-bindings.xml</attribute>
  <attribute name="StoreFactoryClassName">org.jboss.services.binding.XMLServicesStoreFactory</attribute>
</mbean>

 

Once enabled, the Service Binding Manager service would be called as part of the deployment process for every mbean, after the mbean was instantiated and registered in JMX but before any create() lifecycle callback was invoked. The Service Binding Manager service would compare the name of the mbean to its set of binding override configurations, and if a match was found, invoke JMX setAttribute operations to reconfigure the mbean to use a different set of bindings.

 

Basic Service Binding Manager Usage in AS 5

 

In AS 5, the mbean declaration for jboss:service=WebService has its "Port" attribute value injected from the Service Binding Manager service:

 

<!-- A mini webserver used for dynamic and class and resource loading -->
<mbean code="org.jboss.web.WebService" name="jboss:service=WebService">
   ...
   <attribute name="Port">
      <!-- Get the port to use from ServiceBindingManager. -->
      <value-factory bean="ServiceBindingManager" method="getIntBinding" 
                     parameter="jboss:service=WebService"></value-factory>
   </attribute>
   ...
</mbean>

 

The value-factory element basically says, "use the 'ServiceBindingManager' bean as a factory for this value. To get the value, invoke the 'getIntBinding' method that takes a single parameter, passing 'jboss:service=WebService' as the parameter value.

 

The ServiceBindingManager bean exposes a number of different methods for providing values besides the getIntValue shown here. See below for details.

 

The above example uses an mbean from a -service.xml file as an example.  An equivalent value-factory element could be included in a POJO service declaration in a -jboss-beans.xml.

 

This use of ServiceBindingManager as a factory means the service has to be available, i.e. it is no longer disabled by default. Instead, the ServiceBindingManager service is initiated as part of the bootstrap of the server.  How the ServiceBindingManager service is deployed depends on the JBoss AS release:

 

AS 5.0.0 and 5.0.1:

 

The ServiceBindingManager is deployed via the inclusion of its conf/bootstrap/bindings.xml configuration file in the list of initial bootstrap configurations in conf/bootstrap.xml.

 

AS 5.1.0:

 

The ServiceBindingManager is deployed via the conf/bindings-beans file, which is an exploded archive. The SBM's configuration is located in the conf/bindings-beans/META-INF/bindings-jboss-beans.xml file. This archive is deployed early in the startup process, after the contents of conf/bootstrap.xml but before the contents of conf/jboss-service.xml.

 

Configuring the AS 5 Service Binding Manager

 

The configuration of the ServiceBindingManager involves three primary elements :

 

  1. A set of beans containing standard (i.e. default) binding configuration data.  These are the base values (e.g. JNDI on 1099) used to drive ports-default, ports-01 etc.
  2. A number of beans defining "ServiceBindingSets", e.g. ports-default, ports-01, ports-02. The sets of standard bindings are combined with each of these, along with an offset value (e.g. 100 for ports-01) that should be applied to the standard port values to create the binding values for that set.
  3. The ServiceBindingManager service bean itself. This has the standard bindings and the ServiceBindingSets injected into it. It is also configured with the name of the binding set the particular AS instance should use. This is equivalent to the old ServerName mbean attribute in JBoss 4.x. For AS 5 we've made this configurable from the command line by using a system property jboss.service.binding.set. Default value is ports-default.

 

We'll now describe each of these in more detail.  All are found in the conf/bindings.beans/META-INF/bindings-jboss-beans.xml file (conf/bootstrap/bindings.xml in AS 5.0.x).

 

Configuring the Standard Bindings

 

The standard bindings are configured via a bean named "StandardBindngs" which is actually just a HashSet<ServiceBindingMetadata>. Each ServiceBindingMetadata in the set contains configuration information for a particular socket.  Here's a redacted portion of the StandardBindings configuration, showing a representative sample of ServiceBindingMetadata objects.

   <!-- Base binding metadata that ServiceBindingStore uses to create bindings for each set -->
   <bean name="StandardBindings" class="java.util.HashSet" 
         elementClass="org.jboss.services.binding.ServiceBindingMetadata">
      <constructor>
         <parameter>
            <set>
            
            <!-- Naming Service -->
            <bean class="org.jboss.services.binding.ServiceBindingMetadata">
               <property name="serviceName">jboss:service=Naming</property>
               <property name="bindingName">Port</property>
               <property name="port">1099</property>
               <property name="description">The listening socket for the Naming service</property>
            </bean>

            <bean class="org.jboss.services.binding.ServiceBindingMetadata">
               <property name="serviceName">jboss:service=Naming</property>
               <property name="bindingName">RmiPort</property>
               <property name="port">1098</property>
               <property name="description">Socket Naming service uses to receive RMI requests from client proxies</property>
            </bean>

            <!-- Remote classloading service -->
            <bean class="org.jboss.services.binding.ServiceBindingMetadata">
               <property name="serviceName">jboss:service=WebService</property>
               <property name="port">8083</property>
               <property name="description">Socket for dynamic class and resource loading</property>
            </bean>

            .....            

            <bean class="org.jboss.services.binding.ServiceBindingMetadata">
               <property name="serviceName">jboss:service=HAJNDI</property>
               <property name="bindingName">AutoDiscovery</property>
               <property name="hostName">${jboss.partition.udpGroup:230.0.0.4}</property>
               <property name="port">1102</property>
               <property name="description">Multicast socket on which HA-JNDI listens for auto-discovery requests from clients</property>
               <!-- This address should not be changed between different 
                    binding sets; all nodes need to listen on the same 
                    multicast address -->
               <property name="fixedHostName">true</property>
               <!-- This port should not be changed between different 
                    binding sets; all nodes need to listen on the same port -->
               <property name="fixedPort">true</property>
            </bean>

            -----

            </set>
         </parameter>
      </constructor>
   </bean>

 

 

A ServiceBindingMetadata bean exposes the following property setters:

 

  • serviceName -- the name of service to which the binding applies. This is the same value passed to the ServiceBindingManager via the "parameter" attribute of the value-factory element.  It can be any arbitrary string, although use of the relevant service's object name or bean name is a best practice. The serviceName must be specified and cannot be null.
  • bindingName -- an additional qualifier to the serviceName, for services that create more than one socket. The combination of a serviceName and a bindingName uniquely identifies a ServiceBinding. The value for bindingName can be null or unspecified, as it usually is in cases like the jboss:service=WebService example above where only a single binding is used for a particular service. Note that null is not some sort of wildcard value; a request that passes a null binding name parameter will not match a ServiceBinding with a non-null bindingName (or vice-versa).
  • description -- an optional human-friendly description of the binding. Can be displayed by management tools. Note that this property does not exist in AS 5.0.x.
  • hostName -- host name or IP address to which the socket should be bound. In most cases, this is unspecified, and the default host name for the ServiceBindingSet (see below) is used. However, this can be specified if a particular address should be used for a particular binding. The jboss:service=HAJNDI AutoDiscovery example shown above is a good example of such a case; the configuration is for a multicast socket, so the hostName property is used to configure the multicast address.
  • port -- the port to which the socket should be bound
  • fixedHostName -- whether runtime ServiceBindings created from this metadata are not allowed to override the hostName property value to use the defaultHostName value from the specified ServiceBindingSet (see below).  By default this is true if a hostName is configured, false otherwise
  • fixedPort -- whether runtime ServiceBindings created from this metadata are not allowed to override the port property configuration to add the portOffset value from the specified ServiceBindingSet (see below).  By default this is false, since it is the addition of the portOffset that results in unique port numbers and no port conflicts.  However, in some cases the port should remain the same no matter what binding set is used, particularly for multicast sockets, so fixedPort would be set to true. The jboss:service=HAJNDI AutoDiscovery example shown above is a good example of such a case.

 

The following three properties are also supported for advanced cases:

 

  • serviceBindingValueSource -- an implementation of the org.jboss.services.binding.ServiceBindingValueSource interface. An extension point to allow customized behavior beyond the default usages that ship with JBoss AS. See below for details. May be null and usually is.
  • serviceBindingValueSourceClassName -- convenience property for cases where a serviceBindingValueSource needs to be set, but the relevant object can simply be instantiated via reflection using its class' default constructor. Specifies the fully qualified class name of the value source. May be null and usually is.
  • serviceBindingValueSourceConfig -- allows injection of a configuration object that the serviceBindingValueSource (if there is one) understands. What the object is entirely depends on what the serviceBindingValueSource requires. May be null and usually is.

 

Note that the fact that a binding configuration bean exists in the StandardBindings set does not mean that a socket will be opened on that port. A socket is opened by a service, e.g. JNDI; the configuration information in the ServiceBindingManager is simply a set of information that a service can use. It is quite possible the StandardBindings set will include information for services that are not actually deployed. For example, AS 5.1 includes configuration information for JBoss Messaging 2.0, which doesn't ship with AS 2.1 and hasn't even been released at the time AS 5.1 was released. The configurations for JBM 2 are included simply to make it easier to install JBM 2 when it is released.

 

Configuring the Service Binding Sets

 

Each set of bindings that the server supports gets its own MC bean of type ServiceBindingSet. For example:

 

   <!-- The ports-default bindings are obtained by taking the base bindings and adding 0 to each port value  -->
   <bean name="PortsDefaultBindings"  class="org.jboss.services.binding.impl.ServiceBindingSet">
      <constructor>
         <!--  The name of the set -->
         <parameter>ports-default</parameter>
         <!-- Default host name -->
         <parameter>${jboss.bind.address}</parameter>
         <!-- The port offset -->
         <parameter>0</parameter>
         <!-- Set of bindings to which the "offset by X" approach can't be applied -->
         <parameter><null/></parameter>
      </constructor>
   </bean>

   <!-- The ports-01 bindings are obtained by taking the base bindings and adding 100 to each port value -->
   <bean name="Ports01Bindings" class="org.jboss.services.binding.impl.ServiceBindingSet">
      <constructor>
         <!--  The name of the set -->
         <parameter>ports-01</parameter>
         <!-- Default host name -->
         <parameter>${jboss.bind.address}</parameter>
         <!-- The port offset -->
         <parameter>100</parameter>
         <!-- Set of bindings to which the "offset by X" approach can't be applied -->
         <parameter><null/></parameter>
      </constructor>
   </bean>

   <!-- The ports-02 bindings are obtained by taking ports-default and adding 200 to each port value -->
   <bean name="Ports02Bindings" class="org.jboss.services.binding.impl.ServiceBindingSet">
      <constructor>
         <!--  The name of the set -->
         <parameter>ports-02</parameter>
         <!-- Default host name -->
         <parameter>${jboss.bind.address}</parameter>
         <!-- The port offset -->
         <parameter>200</parameter>
         <!-- Set of bindings to which the "offset by X" approach can't be applied -->
         <parameter><null/></parameter>
      </constructor>
   </bean>

   <!-- The ports-03 bindings are obtained by taking ports-default and adding 300 to each port value -->
   <bean name="Ports03Bindings" class="org.jboss.services.binding.impl.ServiceBindingSet">
      <constructor>
         <!--  The name of the set -->
         <parameter>ports-03</parameter>
         <!-- Default host name -->
         <parameter>${jboss.bind.address}</parameter>
         <!-- The port offset -->
         <parameter>300</parameter>
         <!-- Set of bindings to which the "offset by X" approach can't be applied -->
         <parameter><null/></parameter>
      </constructor>
   </bean>

 

ServiceBindingSet exposes the following configuration properties via constructor injection:

 

  • name -- the name of the binding set. Cannot be null
  • defaultHostName -- default host name to use for bindings associated with this set. This is the usual place to configure binding interfaces, and, as can be seen in the example, by default is set to the jboss.bind.address system property, which in turn is set via the -b command line switch.  May be null, in which case the default will be the host machine's loopback address.
  • portOffset -- offset to apply to the ServiceBindingMetadata's port value for bindings associated with this set.
  • overrideBindings -- a Set<ServiceBindingMetadata> containing binding configurations that apply only to this binding set, either non-standard bindings or ones that override standard binding configurations in some custom manner beyond the use of defaultHostName and portOffset. May be null and usually is.

 

Configuring the ServiceBindingManager Bean

 

The configuration of the ServiceBindingManager bean itself is less likely to be changed by an end user. The key configuration is the name of the binding set the particular AS instance should use. But, AS 5 by default injects the value of a system property for this, making it easily configurable from the command line. So typically this portion of the XML wouldn't be edited.

 

For completeness, here are the actual configurations.  These differ somewhat in AS 5.0.x vs. 5.1 and later.

 

AS 5.0.x:

   <bean name="ServiceBindingManager" class="org.jboss.services.binding.ServiceBindingManager">

      <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.system:service=ServiceBindingManager", exposedInterface=org.jboss.services.binding.ServiceBindingManagerMBean.class, registerDirectly=true)</annotation>
            
      <constructor>
         <!-- The name of the set of bindings to use for this server -->
         <parameter>${jboss.service.binding.set:ports-default}</parameter>

         <!-- The named sets of bindings -->
         <parameter>
            <bean name="ServiceBindingStore" class="org.jboss.services.binding.impl.PojoServiceBindingStore">

               <!-- Base bindings that are used to create bindings for each set -->
               <property name="standardBindings"><inject bean="StandardBindings"/></property>
               
               <!-- The sets of bindings -->
               <property name="serviceBindingSets">
                  <set>
                     <inject bean="PortsDefaultBindings"/>
                     <inject bean="Ports01Bindings"/>
                     <inject bean="Ports02Bindings"/>
                     <inject bean="Ports03Bindings"/>
                  </set>
               </property>
            </bean>
         </parameter>
      </constructor>

   </bean>

 

Here the ServiceBindingManager bean has two constructor-injected properties:

  • The name of the binding set this server should use. Again, we've made this configurable from the command line by using a system property jboss.service.binding.set. Default value is ports-default.

  • An implementation of the org.jboss.services.binding.ServiceBindingStore interface, from which the SBM resolves binding value requests. The ServiceBindingStore we're using here is the standard implementation, org.jboss.services.binding.impl.PojoServiceBindingStore.

 

The PojoServiceBindingStore itself has the StandardBindings and a reference to each ServiceBindingSet property injected into it.

 

 

AS 5.1+:

 

   <!-- The actual SBM from which services obtain binding information -->
   <bean name="ServiceBindingManager" class="org.jboss.services.binding.ServiceBindingManager">

      <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.system:service=ServiceBindingManager", exposedInterface=org.jboss.services.binding.ServiceBindingManagerMBean.class, registerDirectly=true)</annotation>
      
      <!-- Here we use the ServiceBindingManagementObject as a factory to create the SBM -->
      <constructor factoryMethod="getServiceBindingManager">     
         <factory bean="ServiceBindingManagementObject"/>
      </constructor>

   </bean>

   <!-- Provides management tools with a ProfileService ManagementView 
        interface to the SBM and its components -->
   <bean name="ServiceBindingManagementObject" 
         class="org.jboss.services.binding.managed.ServiceBindingManagementObject">
         
      <constructor>
         <!-- The name of the set of bindings to use for this server -->
         <parameter>${jboss.service.binding.set:ports-default}</parameter>
          
         <!--  The binding sets -->
         <parameter>
            <set>
               <inject bean="PortsDefaultBindings"/>
               <inject bean="Ports01Bindings"/>
               <inject bean="Ports02Bindings"/>
               <inject bean="Ports03Bindings"/>
            </set>
         </parameter>
         
         <!-- Base binding metadata that is used to create bindings for each set -->
         <parameter><inject bean="StandardBindings"/></parameter>
         
      </constructor>
   </bean>

 

In AS 5.1, a new bean, the ServiceBindingManagementObject, has been added. It's function is toexpose a management interface for use by tools like Jopr and JON that can work with the AS 5 ProfileService's management view. The StandardBindings bean, the various ServiceBindingSets and name of the set to use are injected into this bean. The ServiceBindingManagementObject then serves as a factory that creates the actual ServiceBindingManager bean.

 

More Binding Examples

 

Multiple Bindings for the Same Service

 

The above jboss:service=WebService examples illustrate the most common case, where a particular service only has one binding, of type int.  However, not all services are so simple; a slightly more complicated case involves multiple int bindings.  An example of this is the Naming service (JNDI), which has both a "port" and an "rmiPort".

 

As shown above, this kind of case is handled by declaring mulitple ServiceBindingMetadata beans for the service:

 

<bean class="org.jboss.services.binding.ServiceBindingMetadata">
   <property name="serviceName">jboss:service=Naming</property>
   <property name="bindingName">Port</property>
   <property name="port">1099</property>
   <property name="description">The listening socket for the Naming service</property>
</bean>

<bean class="org.jboss.services.binding.ServiceBindingMetadata">
   <property name="serviceName">jboss:service=Naming</property>
   <property name="bindingName">RmiPort</property>
   <property name="port">1098</property>
   <property name="description">Socket Naming service uses to receive RMI requests from client proxies</property>
</bean>

 

The usage of the SBM in the Naming service is as follows:

 

<mbean code="org.jboss.naming.NamingService"
      name="jboss:service=Naming"
      xmbean-dd="resource:xmdesc/NamingService-xmbean.xml">
      
   <attribute name="Port">
      <value-factory bean="ServiceBindingManager" method="getIntBinding">
         <parameter>jboss:service=Naming</parameter>
         <parameter>Port</parameter>
      </value-factory>
   </attribute>

   ...

   <attribute name="RmiPort">
      <value-factory bean="ServiceBindingManager" method="getIntBinding">
         <parameter>jboss:service=Naming</parameter>
         <parameter>RmiPort</parameter>
      </value-factory>
   </attribute>

   ...
</mbean

 

Here instead of using the value-factory element's parameter attribute to pass the serviceName, we use nested parameter elements to pass both the serviceName and the desired bindingName.

 

Bind Address Injections

 

The ServiceBindingManager contains information about both the port to use for a service's socket(s) and the interface to use. However, in AS 5.0.x, most service's configurations did not obtain their interface configuration from the SBM, instead using the legacy approach of injecting the value of the jboss.bind.address system property. In AS 5.1, this has been changed; interface configurations now come from the SBM (but still, in the end, default to the value of the jboss.bind.address system property).

 

Following is an example of how the Naming service configures socket interfaces using the SBM:

 

<mbean code="org.jboss.naming.NamingService"
      name="jboss:service=Naming"
      xmbean-dd="resource:xmdesc/NamingService-xmbean.xml">
   
      .....
   
      <!-- The bootstrap JNP server bind address. This also sets the default
         RMI service bind address. Empty == all addresses
      -->
      <attribute name="BindAddress">
         <value-factory bean="ServiceBindingManager" method="getStringBinding">
            <parameter>jboss:service=Naming</parameter>
            <parameter>Port</parameter>
            <parameter><null/></parameter>
         </value-factory>
      </attribute>

      .....

      <!-- The RMI service bind address. Empty == all addresses  -->
      <attribute name="RmiBindAddress">
         <value-factory bean="ServiceBindingManager" method="getStringBinding">
            <parameter>jboss:service=Naming</parameter>
            <parameter>RmiPort</parameter>
            <parameter><null/></parameter>
         </value-factory>
      </attribute>

 

There are a couple of significant differences between this example and the one just above where the ports for the same sockets were configured:

  • First, the value of the method attribute is getStringBinding rather than getIntBinding.  The getStringBinding method returns values of type String, generally based on the binding's hostName property.
  • Second, the nested set of parameter elements includes 3 parameters versus the 2 for the port configurations. The third parameter would be an input for a string replacement transformation (see below), but in this case we are not doing any sort of complex transformation, so we simply pass null.

 

String Replacement Transformations

 

In some cases, the binding value is embedded in other content, typically either in a configuration property of String or Element type.  These cases are handled by marking the place of the binding with a known marker, and then asking ServiceBindingManager to perform a String.replace() operation.

 

String Replacement with a Configuration Property of Type String

 

Here, for our example we use the UnifiedInvokerConnector's configuration.

 

First, the declaration in bindings.xml, which is straightforward:

 

<bean class="org.jboss.services.binding.ServiceBindingMetadata">
   <property name="serviceName">UnifiedInvokerConnector</property>
   <property name="port">4446</property>
   <property name="description">Socket for JBoss Remoting Connector used by UnifiedInvoker</property>
</bean>

 

Now, the usage in deploy/remoting-jboss-beans.xml:

 

   <!-- Remoting server configuration -->

   <bean name="UnifiedInvokerConfiguration" class="org.jboss.remoting.ServerConfiguration">

      .....
   

      <!-- Parameters visible to both client and server -->

      <property name="invokerLocatorParameters">
         <map keyClass="java.lang.String" valueClass="java.lang.String">
            <entry>
               <key>serverBindAddress</key>
               <value>
                  <value-factory bean="ServiceBindingManager" method="getStringBinding">
                     <parameter>UnifiedInvokerConnector</parameter>
                     <parameter>${host}</parameter>
                  </value-factory>
               </value>
            </entry>
            <entry>
               <key>serverBindPort</key>
               <value>
                  <value-factory bean="ServiceBindingManager" method="getStringBinding">
                     <parameter>UnifiedInvokerConnector</parameter>
                     <parameter>${port}</parameter>
                  </value-factory>
               </value>
            </entry>

 

Here we're using the SBM's getStringBinding method.  We pass two parameters, the first of which is the usual serviceName.  The second is an input to the SBM's string replacement method, with ${host} and ${port} serving as the respective markers of the values to be replaced. Use of ${host} tells the SBM to use the binding's host name as the source value; use of ${port] tells the SBM to use the port.

 

String Replacement with a Configuration Property of Type Element

 

A similar approach can be followed when the configuration property is an Element. None of the real services in the AS use this approach, so here we use a fake example.

 

Again, the bindings.xml content is straightforward:

 

<bean class="org.jboss.services.binding.ServiceBindingMetadata">
   <property name="serviceName">StringReplacementElementExample</property>
   <property name="port">9999</property>
   <property name="description">Example of String replacement in an Element</property>
</bean>

 

The mbean configuration is more complex:

 

<mbean code="org.jboss.example.SBM"
     name="jboss.example:service=example">

  <attribute name="Configuration">
    <value-factory bean="ServiceBindingManager method="getElementBinding">
      <parameter>StringReplacementElementExample</parameter>
        <parameter><![CDATA[
          <config>
            <invoker transport="bisocket">            
              <attribute name="serverBindAddress">${host}</attribute>
              <attribute name="serverBindPort">${port}</attribute>
              <!--
              <attribute name="secondaryBindPort">7777</attribute>
              <attribute name="serverBindPort">8888</attribute>
              -->
           </invoker>
        </config>
   \]\]\>
      </parameter>
    </value-factory>
  </attribute>
</mbean>

 

All this just to convert that "${port}" in the middle into "9999" and the "${host}" into the value of jboss.bind.address. Note that if the above mbean were converted to a pojo, the Element configuration would be unnecessary and a simple int injection could be done on the serverBindPort property.  Note also the commented out secondaryBindPort and secondaryConnectPort attributes.  If those were uncommented, this simple string replacement approach would not be sufficient. Either a more complex XSL transformation would have to be done, or the mbean would need to be converted into a pojo and handled like the Naming service example above.

XSL Transformation

The final major type of binding configuration in AS 4.x is the conversion of complex documents like JBoss Web's server.xml via XSL Transformation.  The basic approach is the same in AS 5 -- the ServiceBindingManager is provided the location of an input document, it performs an XSL transform on the document and saves it as a temp file, and the location of the temp file is used in the target service's configuration instead of the location of the original document.  Here's how it's done for the server.xml use case.  First, the binding.xml configuration:
<bean class="org.jboss.services.binding.ServiceBindingMetadata">
   <property name="serviceName">jboss.web:service=WebServer</property>
   <property name="port">8080</property>
   <property name="description">JBoss Web HTTP connector socket; also drives the values for the HTTPS and AJP sockets</property>

   <!--
      Inject a XSLT transform configuration (see below) that describes
      how to transform server.xml
      If the binding value request doesn't require an XSL Transform, this config
      will be ignored.
   -->
   <property name="serviceBindingValueSourceConfig"><inject bean="JBossWebConnectorXSLTConfig"/></property>
</bean>
Here we expand upon previous usage of ServiceBinding to include the injection of a complex config object that can provide additional configuration information to the SBM. Here we're injecting a bean that includes information on how to do an XSL Transformation.  The bean is declared at the bottom of the binding.xml file. It could be nested in the property element, but that would get pretty messy:
<!-- XSL Transform to apply to server.xml -->
<bean name="JBossWebConnectorXSLTConfig" 
      class="org.jboss.services.binding.impl.XSLTServiceBindingValueSourceConfig">
   <constructor>
      <parameter><![CDATA[
   <xsl:stylesheet
         xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>

     <xsl:output method="xml" ></xsl:output>
     <xsl:param name="port"></xsl:param>

     <xsl:variable name="portAJP" select="$port - 71"></xsl:variable>
     <xsl:variable name="portHttps" select="$port + 363"></xsl:variable>

     <xsl:template match="/">
       <xsl:apply-templates></xsl:apply-templates>
     </xsl:template>

      <xsl:template match = "Connector">
         <Connector>
            <xsl:for-each select="@*">
            <xsl:choose>
               <xsl:when test="(name() = 'port' and . = '8080')">
                  <xsl:attribute name="port"><xsl:value-of select="$port" ></xsl:value-of></xsl:attribute>
               </xsl:when>
               <xsl:when test="(name() = 'port' and . = '8009')">
                  <xsl:attribute name="port"><xsl:value-of select="$portAJP" ></xsl:value-of></xsl:attribute>
               </xsl:when>
               <xsl:when test="(name() = 'redirectPort')">
                  <xsl:attribute name="redirectPort"><xsl:value-of select="$portHttps" ></xsl:value-of></xsl:attribute>
               </xsl:when>
               <xsl:when test="(name() = 'port' and . = '8443')">
                  <xsl:attribute name="port"><xsl:value-of select="$portHttps" ></xsl:value-of></xsl:attribute>
               </xsl:when>
               <xsl:otherwise>
                  <xsl:attribute name="{name()}"><xsl:value-of select="." ></xsl:value-of></xsl:attribute>
               </xsl:otherwise>
            </xsl:choose>
            </xsl:for-each>
            <xsl:apply-templates></xsl:apply-templates>
         </Connector>
      </xsl:template>

     <xsl:template match="*|@*">
       <xsl:copy>
         <xsl:apply-templates select="@*|node()"></xsl:apply-templates>
       </xsl:copy>
     </xsl:template>
   </xsl:stylesheet>
   \]\]\>
      </parameter>
   </constructor>
</bean>

 

Here's the usage of this in the war-deployer-jboss-beans.xml:

 

<bean name="WarDeployer" class="org.jboss.web.tomcat.service.deployers.TomcatDeployer">
      
   .....
   <property name="configFile">
      <value-factory bean="ServiceBindingManager" method="getResourceBinding">
         <parameter>jboss.web:service=WebServer</parameter>
         <parameter>${jboss.server.home.url}${/}deploy${/}jbossweb.sar${/}server.xml</parameter>
      </value-factory>
   </property>

   .....

</bean>

 

The SBM's getResourceBinding methods return a String which be used as a filesystem path.

Creation of Default Values by the Target Service

 

Some service providers (e.g. the EJB3 team) may not wish to have their standard/default port configuration information externalized from their configuration files, but still want to retain the benefits of the ServiceBindingManager. The SBM supports this type of usage, by providing overloaded versions of all the getXXXMethods that take additional hostName and basePort parameters. In these cases, there is no entry for the binding in bindings-jboss-beans.xml. Rather, the service that needs the binding information provides the defaults when it requests the binding. For example:

 

  <bean name="org.jboss.ejb3.RemotingConnector"
    class="org.jboss.remoting.transport.Connector">

    <property name="invokerLocator">


      <value-factory bean="ServiceBindingManager"
        method="getStringBinding">
        <parameter>
          jboss.remoting:type=Connector,name=DefaultEjb3Connector,handler=ejb3
        </parameter>
        <parameter>
          <null />
        </parameter>
        <parameter>socket://${host}:${port}</parameter>
        <parameter>
          <null />
        </parameter>
        <parameter>3873</parameter>
      </value-factory>

    </property>

    .....

  </bean>

 

The result of this configuration is the SBM's getStringBinding(String serviceName, String bindingName, String input, String hostName, int basePort) method will be invoked to provide the binding. The bindingName param's value is null since this service only needs a single binding and thus doesn't need to qualify the name.  The input parameter is passed a String upon which a string replacement operation will be performed.  The hostName parameter is null, so the resulting binding will use the default host name from the binding set.  The basePort to which any binding set's portOffset should be applied is 3873.

 

When the getStringBinding(String serviceName, String bindingName, String input, String hostName, int basePort) method is invoked, the following logic is applied:

 

  1. The SBM checks if the active binding set has any existing binding information for the given serviceName and bindingName. If yes, the binding value is derived from the existing binding information and the hostName and basePort parameters are ignored.
  2. If there is no existing binding information, a new ServiceBindingMetadata is created from the serviceName, bindingName, hostName, and basePort parameters. This ServiceBindingMetadata is added to the set of override bindings for the active binding set and a new then the binding value is calculated and returned.

 


Implementation Details

Operations Exposed by the ServiceBindingManager

So far our examples have focused on using ServiceBindingManager as a value factory for int values, via its getIntBinding method.  But not all requests are for int bindings.  The following lists the full set of value factory methods exposed by ServiceBindingManager:
public int getIntBinding(String serviceName, String bindingName) throws NoSuchBindingException

public int getIntBinding(String serviceName) throws NoSuchBindingException

public InetAddress getInetAddressBinding(String serviceName, String bindingName) throws NoSuchBindingException

public InetAddress getInetAddressBinding(String serviceName) throws NoSuchBindingException

public String getStringBinding(String serviceName, String bindingName, String input) throws NoSuchBindingException

public String getStringBinding(String serviceName, String input) throws NoSuchBindingException

public String getStringBinding(String serviceName) throws NoSuchBindingException
   
public Element getElementBinding(String serviceName, String bindingName, Element input) throws NoSuchBindingException

public Element getElementBinding(String serviceName, Element input) throws NoSuchBindingException

public String getResourceBinding(String serviceName, String bindingName, String input) throws NoSuchBindingException
   
public String getResourceBinding(String serviceName, String input) throws NoSuchBindingException
   
public URL getURLBinding(String serviceName, String bindingName, String input) throws NoSuchBindingException

public URL getURLBinding(String serviceName, String input) throws NoSuchBindingException

public Object getGenericBinding(String serviceName, String bindingName, Object ... params) throws NoSuchBindingException

public Object getGenericBinding(String serviceName, Object ... params) throws NoSuchBindingException

 

Some notes on the above:

  • The overloaded methods that don't take a bindingName param are simple convenience methods that pass null to those that do.
  • The methods that return a String or an Element accept an optional input param. If provided, the SBM will attempt to perform a transformation on the input value in order to create the return value.  See examples below.
  • The getResourceBinding methods are meant to support use cases similar to the JBoss Web server.xml case, where the value of the input parameter is the filesystem path of a resource. Typical usage would be to have the SBM perform a transformation on the content of that resource, storing the output in a different location, and then returning the filesystem path of the transformed output.
  • The getURLBinding methods are similar to the getResourceBinding methods, except the input parameter is a URL and the return value is a URL
  • The getGenericBinding methods allows the SBM to be extended to provide arbitrary types. The target binding must have a ServiceBindingValueSource configured, one that understands how to process the params argument.

 

In addition to the above methods, the ServiceBindingManager also supports the following overloaded methods that allow services to create their own binding configurations, as was discussed in the previous section.

 

public int getIntBinding(String serviceName, String bindingName, 
         String hostName, int basePort)
      throws UnknownHostException, DuplicateServiceException
 
public int getIntBinding(String serviceName, String bindingName, 
         String hostName, int basePort, boolean fixedPort, boolean fixedHostName)
      throws UnknownHostException, DuplicateServiceException
 
public InetAddress getInetAddressBinding(String serviceName, String bindingName, 
         String hostName, int basePort)
      throws UnknownHostException, DuplicateServiceException
 
public InetAddress getInetAddressBinding(String serviceName, String bindingName, 
         String hostName, int basePort, boolean fixedPort, boolean fixedHostName)
      throws UnknownHostException, DuplicateServiceException
 
public String getStringBinding(String serviceName, String bindingName, String input, 
         String hostName, int basePort)
      throws UnknownHostException, DuplicateServiceException
 
public String getStringBinding(String serviceName, String bindingName, String input, 
         String hostName, int basePort, boolean fixedPort, boolean fixedHostName)
      throws UnknownHostException, DuplicateServiceException
 
public Element getElementBinding(String serviceName, String bindingName, Element input, 
         String hostName, int basePort)
      throws UnknownHostException, DuplicateServiceException
 
public Element getElementBinding(String serviceName, String bindingName, Element input, 
         String hostName, int basePort, boolean fixedPort, boolean fixedHostName)
      throws UnknownHostException, DuplicateServiceException
 
public String getResourceBinding(String serviceName, String bindingName, String input, 
         String hostName, int basePort)
      throws UnknownHostException, DuplicateServiceException
 
public String getResourceBinding(String serviceName, String bindingName, String input, 
         String hostName, int basePort, boolean fixedPort, boolean fixedHostName)
      throws UnknownHostException, DuplicateServiceException
 
public URL getURLBinding(String serviceName, String bindingName, URL input, 
         String hostName, int basePort)
      throws UnknownHostException, DuplicateServiceException
 
public URL getURLBinding(String serviceName, String bindingName, URL input, 
         String hostName, int basePort, boolean fixedPort, boolean fixedHostName)
      throws UnknownHostException, DuplicateServiceException

 

If the given binding information is not available, a new binding will be created using the given serviceName, bindingName, hostName, basePort, fixedPort and fixedHostName values.  The overloaded versions that do not take the fixedPort and fixedHostName parameters simple pass false to those that do.

 

The ServiceBinding Class and the ServiceBindingValueSource Interface Hierarchy

Most of the content of the bindings.xml file is used to create ServiceBinding objects.  These are simple data objects that provide information to SBM to tell it how to respond to a getXXXBinding request.  ServiceBinding exposes the following properties:
public String getServiceName()

public String getBindingName()

public String getHostName()

public InetAddress getBindAddress()

public int getPort()

public ServiceBindingValueSource getServiceBindingValueSource()

public void setServiceBindingValueSource(ServiceBindingValueSource serviceBindingValueSource)

public String getServiceBindingValueSourceClassName()

public void setServiceBindingValueSourceClassName(String serviceBindingValueSourceClassName)

public Object getServiceBindingValueSourceConfig()

public void setServiceBindingValueSourceConfig(Object serviceBindingValueSourceConfig)
The serviceName, bindingName, hostName, bindAddress and port properties provide the basic description of the binding.  In most cases, those are the only properties used with a particular ServiceBinding.  The serviceBindingValueSourceConfig property allows injection of arbitrary information that can be used by the SBM in creating configuration values associated with the binding (an example of this can be seen in the XSL transformation examples below). The serviceBindingValueSource and serviceBindingValueSourceClassName properties are extension points to allow customized behavior beyond the default usages that ship with JBoss AS.  When SBM receives a request for a binding value, it looks up the desired ServiceBinding object. If no matching binding is found, NoSuchBindingException is thrown. If a binding is available, SBM goes through a process (detailed below) to obtain an instance of the ServiceBindingValueSource interface, from which it obtains the value to return to the caller.  The ServiceBindingValueSource interface is as follows:
public interface ServiceBindingValueSource 
{
   /**
    * Returns a detyped binding value based on the provided binding
    * and detyped array of parameters.
    * 
    * @param binding the binding. Cannot be <code>null</code>
    * @param params  the parameters, or <code>null</code>
    * 
    * @return the binding value. May return <code>null</code>
    * 
    * @throws IllegalArgumentException if content of <code>params</code> is 
    *                                  not understood
    * @throws Exception if another exception occurs
    */
   public Object getServiceBindingValue(ServiceBinding binding, Object ... params) throws Exception;
}

 

ServiceBindingValueSource has a number of subinterfaces which expose more strongly typed methods. For example, an impl optimized for returning int values could implement this subinterface:

 

public interface IntServiceBindingValueSource extends ServiceBindingValueSource
{
   /**
    * Returns the int to use for the binding value.
    * 
    * @param binding the binding. Cannot be <code>null</code>
    * @return an int to use as the binding value
    */
   int getIntServiceBindingValue(ServiceBinding binding) throws Exception;
}

 

If SBM gets a request to its getIntBinding method and it determines that the relevant ServiceBindingValueSource implements IntServiceBindingValueSource, it will use the getIntServiceBindingValue(ServiceBinding binding) method instead of trying to convert into an int the Object returned by getServiceBindingValue(ServiceBinding binding, Object ... params).  The following ServiceBindingValueSource subinterfaces are supported. See source code or javadoc for details:


  • IntServiceBindingValueSource
  • InetAddressServiceBindingValueSource
  • StringServiceBindingValueSource
  • ElementServiceBindingValueSource
  • URLServiceBindingValueSource

Obtaining the ServiceBindingValueSource

When the SBM handles a request for a binding value, after it locates the ServiceBinding, it goes through the following algorithm to obtain the ServiceBindingValueSource


  1. Invoke the getServiceBindingValueSource() method on the ServiceBinding.
    1. if the ServiceBinding has had a value source dependency injected, it returns that.
    2. else, if it has had a serviceBindingValueSourceClassName dependency injected, it attempts to use the TCCL to load that class and then tries to instantiate it via via Class.newInstance().  This mechanism allows deferred binding of custom ServiceBindingValueSource impls whose type may not be available when the SBM is itself created.
  2. If ServiceBinding.getServiceBindingValueSource() returns null, SBM will attempt to create a default ServiceBindingValueSource whose type depends on the type being requested:
    1. int or InetAddress --> SimpleServiceBindingValueSourceImpl
    2. String --> StringReplacmentServiceBindingValueSourceImpl
    3. Element or URL --> check the ServiceBinding.getServiceBindingValueSourceConfig() property for the presence of an org.jboss.services.binding.impl.XSLTServiceBindingValueSourceConfig. If found, use XSLTServiceBindingValueSourceImpl, else use StringReplacmentServiceBindingValueSourceImpl.
  3. If no default type is known, throws IllegalStateException

The effect of all this is the SBM is extensible, via injection into a ServiceBinding of custom ServiceBindingValueSource impls or classnames along with any needed configuration objects. But for the standard use cases, the SBM picks intelligent defaults, allowing the elimination of a lot of boilerplate configuration XML.

Standard ServiceBindingValueSource Implementations

SimpleServiceBindingValueSourceImpl

Implements IntServiceBindingValueSource and InetAddressServiceBindingValueSource.  If an int is requested, returns the value of the port property of the passed in ServiceBinding.  If an InetAddress is requested, returns the value of ServiceBinding.getBindAddress().

StringReplacmentServiceBindingValueSourceImpl

Implements StringServiceBindingValueSource, ElementServiceBindingValueSource and URLServiceBindingValueSource.  If a String is requested, behavior depends on whether an input value was passed by SBM.  If an input was provided, uses the String.replace() method to replace any appearances of ${host} in input with ServiceBinding.getHostName(), and any appearances of ${port}
with ServiceBinding.getPort().  If no input is provided, returns ServiceBinding.getHostName().

 

If an Element is requested, an input must be provided. The input element is then converted to a String, the String.replace() transformation described above is performed, and the resulting string is reconverted into an Element and returned.  If a URL is requested, an input must be provided. A URLConnection to input is opened and the URL contents read into a String. The String.replace() transformation described above is performed, and the resulting string is written to a temp file. The location of the temp file is returned as a URL. 

 

StringReplacmentServiceBindingValueSourceImpl can optionally be configured with a StringReplacementServiceBindingValueSourceConfig by injecting one into the relevant ServiceBinding. StringReplacementServiceBindingValueSourceConfig exposes hostMarker and portMarker properties, allowing override of the ${host} and ${port} markers used in the String.replace() operations.

 

XSLTServiceBindingValueSourceImpl

 

Works by performing XSL transformations rather than the more simple String.replace() operations performed by StringReplacmentServiceBindingValueSourceImpl. Implements ElementServiceBindingValueSource and URLServiceBindingValueSource.

 

When used, the ServiceBinding must have an instance of org.jboss.services.binding.impl.XSLTServiceBindingValueSourceConfig injected. This class is a simple wrapper around an Element that specifies the XSL transformation to be performed.

 

In all cases, an input must be provided.

 

If an Element is requested, a transformation is performed on input and the result returned.

 

If a URL is requested, a URLConnection to input is opened and the XSL transformation is performed on the contents, with the resulting output written to a temp file. The location of the temp file is returned as a URL.

 

If a String is requested, an attempt is made to convert input to a URL.  If unsuccessful, input is treated as a classpath resource.  Either way an InputStream is opened to read the contents pointed to by input, and the XSL transformation is performed on the contents, with the resulting output written to a temp file. The URL of the temp file is returned as a String.

Attachments:
Average User Rating
(0 ratings)




More Like This

  • Retrieving data ...