Searchable Title: Service Binding Manager in JBoss Application Server 5
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.
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.
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.
The configuration of the ServiceBindingManager involves three primary elements :
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).
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:
The following three properties are also supported for advanced cases:
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.
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:
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.
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.
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:
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.
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.
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.
Here's the usage of this in the war-deployer-jboss-beans.xml: 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:
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:<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>
<!-- 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><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.
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:
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:
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.
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: 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:
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 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)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;
}
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:
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:
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.
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.