Middleware Abstraction Layer¶
To make XTT work with various middlewares, I created an abstraction layer. My primary design requirement has been that users XTT should not need have implicit links to a particular middleware in the code.
This layer does not attempt to provide every bit of functionality, but just enough to get XTT to run.
The basic idea is that the connection information you have in your code specifies three things:- A channel name
- A data selector, which usually specifies at least the type of data that you're interested in
- The type you'd like the data to be converted to
This information will then be mapped to the specific middleware you're using. In particular, the "channel" is an abstract concept that maps to whatever middleware you're using. In XCF, the channel would be a memory, in RSB it would be a scope, and in ROS it would be a topic.
In most cases, the mapping should be transparent to the user. However, in some cases (currently only when using hierarchical scopes on RSB), additional information may be necessary. Here are the mappings that are currently supported:
Common Name | middleware | channel | selector | type |
---|---|---|---|---|
XCF | xcf | memory name | xpath | not used, always XML |
RSB | rsb | scope name | not currently used | class name of the type |
ROS | ros | topic name | n/a | message type name |
Notes¶
- XCF: For the selector, it is commonly quite convenient to use just a the root tag name, e.g. "utterance".
- RSB doesn't require a filter, because the scope name already includes a filter, and the type information is an implicit type filter. Filter expression could be usable, but would need to take into account that different message serializations are not currently inspectable in a common way.
- ROS does not support selectors out of the box, but support for topic_tools could be useful.
Caveats¶
At the moment, the type is fairly specific to the middleware, which still creates a coupling. XTT always uses XML data, so that is not as much of a problem, but to be a general middleware abstraction layer, more capable type mappings would be required. We're working on that -- if you're interested in progress information, send Ingo an e-mail.
Source Code¶
The layer is currently contained in the de.unibi.agai.eb
package of XTT. I'm working on factoring it out, stay stuned!
Using the Layer¶
I will first give a simple example here, and then explain how the defaults can be overriden using property configuration.
Example¶
Lets say our source is called "xtt_test" and its speech recognizer input as XML with an "speech_hyp" tag at the root.
To get the client bus for this configuration, use
TaskBus clientBus = TaskBusFactory.createClientBus("xtt_test", "spech_hyp", nu.xom.Document.class);
This specifies that the channel is "xtt_test", the type on the bus is called "isr", and you'd like to receive the input as an instance of class "nu.xom.Document".
Use with XCF¶
For XCF, no further configuration is required, but you can override some values, if so desired.
By default, the above statement would create a memory-connection to memory "xtt_test", and set up a filter expression called "/speech_hyp". Because XCF always uses XML with nu.xom.Document, it is passed through.
Example for RSB¶
For RSB, we need a bit more information, because it supports different types and uses hierarchical scopes. You'd do it like this:
-Deb.rsb.isr.channel=/isr/hyp -Deb.rsb.isr.type=String
Note that in RSB, selectors are not currently supported, and you have to specify a type (XCF's default and only type is XML, so you need not give it). It still works, because the isr only published hypotheses on that scope.
Configuration in general¶
The layer is configured using environment variables. The names are built as follows:eb.<middleware>.<name>.<variable>
. For example, eb.xcf.speech.type
would be the variable to configure the message type for port "speech", and using the "xcf" middleware.
The layer will search all configured middlewares, so you can easily provide duplicate configurations (e.g. for both XCF and RSB), and the layer will pick the one that is available. If both middleware implementations are available, both will be tried, and the first one that works is chosen. This can result in unpredictable behavior, so there is also a variable called "eb.middleware_order", with comma-separated values. E.g. -Deb.middleware_order=rsb,xcf
can be used to prefer rsb over xcf.