Documentation updates for M3 (INT-167).

This commit is contained in:
Mark Fisher
2008-04-07 20:46:56 +00:00
parent a6392bd142
commit 3ba3f07b96
5 changed files with 221 additions and 62 deletions

View File

@@ -9,8 +9,14 @@
are external to the messaging system. As the name implies, the interaction consists of adapting the external
system or component to send-to and/or receive-from a <interfacename>MessageChannel</interfacename>. Within
Spring Integration, there is a distinction between <emphasis>source adapters</emphasis> and <emphasis>target
adapters</emphasis>. In the 1.0 Milestone 2 release, Spring Integration includes source and target adapters
for JMS, Files, Streams, and Spring ApplicationEvents as well as a target adapter for sending e-mail.
adapters</emphasis>. In the 1.0 Milestone 3 release, Spring Integration includes source and target adapters
for JMS, RMI, Files, Streams, Spring's HttpInvoker and Spring ApplicationEvents. A source adapter for FTP is
also available as well as target adapters for sending e-mail and invoking Web Services.
</para>
<para>
All of these adapters are discussed in this section. However, namespace support is provided for many of them
and is typically the most convenient option for configuration. For examples, see
<xref linkend="namespace-adapters"/>.
</para>
</section>
@@ -65,6 +71,47 @@
Integration's namespace support.
</para>
</section>
<section id="adapters-rmi">
<title>RMI Adapters</title>
<para>
The <classname>RmiSourceAdapter</classname> is built upon Spring's <classname>RmiServiceExporter</classname>.
However, since it is adapting a <interfacename>MessageChannel</interfacename>, there is no need to specify
the <emphasis>serviceInterface</emphasis>. Likewise, the <emphasis>serviceName</emphasis> is automatically
generated based on the channel name. Therefore, creating the adapter is as simple as providing a reference
to its channel: <programlisting>RmiSourceAdapter rmiSourceAdapter = new RmiSourceAdapter(channel);
</programlisting>
</para>
<para>
The <classname>RmiTargetAdapter</classname> encapsulates the creation of a proxy that is capable of
communicating with an <classname>RmiSourceAdapter</classname> running in another process. Since the interface
is already known, the only required information is the URL. The URL should include the host, port (default is
'1099'), and 'serviceName'. The 'serviceName' must match that created by the
<classname>RmiSourceAdapter</classname> (the prefix is available as a constant).
<programlisting>String url = "http://somehost:1099/" + RmiSourceAdapter.SERVICE_NAME_PREFIX + "someChannel";
RmiTargetAdapter rmiTargetAdapter = new RmiTargetAdapter(url);
</programlisting>
</para>
</section>
<section id="adapters-httpinvoker">
<title>HttpInvoker Adapters</title>
<para>
The source and target adapters for HttpInvoker are very similar to the RMI adapters. For a source, only the
channel needs to be provided, and for a target, only the URL. If running in a Spring MVC environment, then
the <classname>HttpInvokerSourceAdapter</classname> simply needs to be defined and provided in a
<interfacename>HandlerMapping</interfacename>. For example, the following would be exposed at the path
"http://somehost/path-mapped-to-dispatcher-servlet/httpInvokerAdapter" when a simple
<classname>BeanNameUrlHandlerMapping</classname> strategy is enabled:
<programlisting><![CDATA[<bean name="/httpInvokerAdapter"
class="org.springframework.integration.adapter.httpinvoker.HttpInvokerSourceAdapter">
<constructor-arg ref="someChannel"/>
</bean>]]></programlisting>
When not running in a Spring MVC application, simply define a servlet in 'web.xml' whose type is
<classname>HttpRequestHandlerServlet</classname> and whose name matches the bean name of the source
adapter. As with the <classname>RmiTargetAdapter</classname>, the
<classname>HttpInvokerTargetAdapter</classname> only requires the URL that matches an instance of
<classname>HttpInvokerSourceAdapter</classname> running in a web application.
</para>
</section>
<section id="adapters-file">
<title>File Adapters</title>
<para>
@@ -78,9 +125,23 @@
adapter also accepts an implementation of the <interfacename>FileNameGenerator</interfacename> strategy that
defines the following method: <programlisting>String generateFileName(Message message)</programlisting>
</para>
</section>
<section id="adapters-ftp">
<title>FTP Adapters</title>
<para>
As with the JMS adapters, the most convenient way to configure File adapters is with the namespace support. For
examples, see <xref linkend="namespace-adapters"/>.
To poll a directory with FTP, configure an instance of <classname>FtpSourceAdapter</classname>. The adapter
expects a number of properties for connecting to the FTP server (as shown below) as well as the
'channel' and the 'period' for polling. For example, the following adapter would poll every 30 seconds:
<programlisting><![CDATA[<bean id="ftpSource"
class="org.springframework.integration.adapter.ftp.FtpSourceAdapter">
<property name="host" value="example.org"/>
<property name="username" value="someuser"/>
<property name="password" value="somepassword"/>
<property name="localWorkingDirectory" value="/some/path"/>
<property name="remoteWorkingDirectory" value="/some/path"/>
<property name="channel" ref="someChannel"/>
<property name="period" value="30000"/>
</bean>]]></programlisting>
</para>
</section>
<section id="adapters-email">
@@ -99,32 +160,69 @@
<programlisting><![CDATA[public interface MailHeaderGenerator {
void populateMailMessageHeader(MailMessage mailMessage, Message<?> message);
}]]></programlisting>
A static implementation is available out-of-the-box, but typically most of the properties would need to be
dynamically generated based on the message itself. The following is an example of a configured
mail adapter.
<programlisting><![CDATA[<bean id="mailTargetAdapter" class="org.springframework.integration.adapter.mail.MailTargetAdapter">
The default implementation will look for attributes in the <classname>MessageHeader</classname> with
the following constants defining the keys:
<programlisting>MailAttributeKeys.SUBJECT
MailAttributeKeys.TO
MailAttributeKeys.CC
MailAttributeKeys.BCC
MailAttributeKeys.FROM
MailAttributeKeys.REPLY_TO</programlisting>
</para>
<para>
A static implementation is also available out-of-the-box and may be useful for testing. However, when
customizing, the properties would typically be generated dynamically based on the message itself. The
following is an example of a configured mail adapter.
<programlisting><![CDATA[<bean id="mailTargetAdapter"
class="org.springframework.integration.adapter.mail.MailTargetAdapter">
<property name="mailSender" ref="javaMailSender"/>
<property name="headerGenerator" ref="dynamicMailMessageHeaderGenerator"/>
</bean>]]></programlisting>
</para>
</section>
<section id="adapters-webservices">
<title>Web Service Adapters</title>
<para>
To invoke a Web Service upon sending a message to a channel, there are two options:
<classname>SimpleWebServiceTargetAdapter</classname> and
<classname>MarshallingWebServiceTargetAdapter</classname>. The former will accept either a
<classname>String</classname> or <interfacename>javax.xml.transform.Source</interfacename> as the message
payload. The latter provides support for any implementation of the <interfacename>Marshaller</interfacename>
and <interfacename>Unmarshaller</interfacename> interfaces. Both require the URI of the Web Service to be
called.<programlisting>simpleAdapter = new SimpleWebServiceTargetAdapter(uri);
marshallingAdapter = new MarshallingWebServiceTargetAdapter(uri, marshaller);
</programlisting>
As with the other target adapters, this can then be referenced from a <classname>MessageEndpoint</classname>
that is subscribed to a channel. The endpoint is then responsible for passing the response to the proper
channel. It will first check for a <emphasis>returnAddress</emphasis> on the original message's header, and it
will fallback to the endpoint's own default output channel.
</para>
<para>
For more detail on the inner workings, see the Spring Web Services reference guide's chapter covering
<ulink url="http://static.springframework.org/spring-ws/site/reference/html/client.html">client access</ulink>
as well as the chapter covering
<ulink url="http://static.springframework.org/spring-ws/site/reference/html/oxm.html">Object/XML mapping</ulink>.
</para>
</section>
<section id="adapters-stream">
<title>Stream Adapters</title>
<para>
Spring Integration also provides adapters for streams. Both <classname>ByteStreamSourceAdapter</classname> and
<classname>CharacterStreamSourceAdapter</classname> extend the <classname>PolllingSourceAdapter</classname> so
that the polling period can be configured, and the Message Bus can automatically detect and schedule them. Both
require an <classname>InputStream</classname> as the single constructor argument. The
that the polling period can be configured, and the Message Bus can automatically detect and schedule them. The
byte stream version requires an <classname>InputStream</classname>, and the character stream version requires a
<classname>Reader</classname> as the single constructor argument. The
<classname>ByteStreamSourceAdapter</classname> also accepts the 'bytesPerMessage' property to determine how many
bytes it will attempt to read into each <interfacename>Message</interfacename>.
</para>
<para>
For target streams, there are also two implementations: <classname>ByteStreamTargetAdapter</classname> and
<classname>CharacterStreamTargetAdapter</classname>. Each defines a constructor that requires an
<classname>OutputStream</classname>, and each provides a second constructor that adds the optional
'bufferSize' property. Since both of these ultimately implement the <interfacename>MessageHandler</interfacename>
interface, they can be referenced from an endpoint configuration as will be described in more detail in
<xref linkend="namespace-endpoint"/>.
<classname>CharacterStreamTargetAdapter</classname>. Each requires a single constructor argument -
<classname>OutputStream</classname> for byte streams or <classname>Writer</classname> for character streams,
and each provides a second constructor that adds the optional 'bufferSize' property. Since both of these
ultimately implement the <interfacename>MessageHandler</interfacename> interface, they can be referenced from an
endpoint configuration as will be described in more detail in <xref linkend="namespace-endpoint"/>.
</para>
</section>
<section id="adapters-applicationevents">

View File

@@ -9,13 +9,11 @@
needs and at what level you prefer to work. As with the Spring framework in general, it is also possible to mix
and match the various techniques according to the particular problem at hand. For example, you may choose the
XSD-based namespace for the majority of configuration combined with a handful of objects that are configured with
annotations. Of course, it is also possible to always stick with a single approach. The main point is that these
are <emphasis>options</emphasis> for configuration motivated by the need to support a user community with a wide
range of preferences. That said, there has also been a concerted effort to provide consistent naming so that, for
example, the XML elements defined by the XSD schema will match the names of annotations, and the attributes of
those XML elements will match the names of annotation properties. Direct usage of the API is yet another option
and is described in detail in <xref linkend="api"/>. We expect that most users will choose one of the
higher-level options, such as the namespace-based or annotation-driven configuration.
annotations. As much as possible, the two provide consistent naming. XML elements defined by the XSD schema will
match the names of annotations, and the attributes of those XML elements will match the names of annotation
properties. Direct usage of the API is yet another option and is described in detail in <xref linkend="api"/>.
We expect that most users will choose one of the higher-level options, such as the namespace-based or
annotation-driven configuration.
</para>
</section>
@@ -33,9 +31,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
]]><emphasis>xmlns:integration="http://www.springframework.org/schema/integration"</emphasis><![CDATA[
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
]]><emphasis>http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd"</emphasis>&gt;</programlisting>
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
]]><emphasis>http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd"</emphasis>&gt;</programlisting>
</para>
<para>
You can choose any name after "xmlns:"; <emphasis>integration</emphasis> is used here for clarity, but you might
@@ -46,9 +44,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
]]><emphasis>xmlns:beans="http://www.springframework.org/schema/beans"</emphasis><![CDATA[
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd">]]></programlisting>
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd">]]></programlisting>
</para>
<para>
When using this alternative, no prefix is necessary for the Spring Integration elements. On the other hand, if
@@ -99,6 +97,17 @@
provided as a comma-delimited list:
<programlisting><![CDATA[<channel id="stringOrNumberChannel" datatype="java.lang.String,java.lang.Number"/>]]></programlisting>
</para>
<para>
To create a <classname>PriorityChannel</classname>, use the "priority-channel" element:
<programlisting><![CDATA[<priority-channel id="exampleChannel"/>]]></programlisting>
By default, the channel will consult the <classname>MessagePriority</classname> value in the
message's header. However, a custom <interfacename>Comparator</interfacename> reference may be
provided instead. Also, the <classname>PriorityChannel</classname> does support the "datatype"
attribute. The following example demonstrates both:
<programlisting><![CDATA[<priority-channel id="exampleChannel"
datatype="example.Widget" comparator-ref="widgetComparator"/>
]]></programlisting>
</para>
<para>
Message channels may also have interceptors as described in <xref linkend="api-channelinterceptor"/>. One or
more &lt;interceptor&gt; elements can be added as sub-elements of &lt;channel&gt;. Provide the "ref" attribute
@@ -177,6 +186,8 @@
]]><emphasis><![CDATA[<concurrency core="5" max="25" queue-capacity="20" keep-alive="120"/>]]></emphasis><![CDATA[
</endpoint>]]></programlisting>
Recall the default concurrency policy values as listed in <xref linkend="api-messagebus-concurrencypolicy"/>.
If no concurrency settings are provided (i.e. a <emphasis>null</emphasis>
<classname>ConcurrencyPolicy</classname>), the endpoint's handler will be invoked in the caller's thread.
</para>
<tip>
The default queue capacity of 0 triggers the creation of a <classname>SynchronousQueue</classname>. In many
@@ -227,16 +238,36 @@
<title>Configuring Channel Adapters</title>
<para>
The most convenient way to configure Channel Adapters is by using the namespace support. The following examples
demonstrate the namespace-based configuration of source and target adapters (Spring Integration 1.0 M1 includes
namespace support for JMS and Files):
demonstrate the namespace-based configuration of several source and target adapters:
<programlisting><![CDATA[
<jms-source connection-factory="connectionFactory" destination="inputQueue" channel="inputChannel1"/
<jms-source connection-factory="connFactory" destination="inQueue" channel="in1"/>
<jms-target connection-factory="connectionFactory" destination="outputQueue" channel="outputChannel1"/>
<!-- using the default "connectionFactory" reference -->
<jms-target destination="outQueue" channel="out1"/>
<file-source directory="/tmp/input" channel="inputChannel2" poll-period="10000"/>
<file-source directory="/tmp/in" channel="in2" poll-period="10000"/>
<file-target directory="/tmp/output" channel="outputChannel2"/>
<file-target directory="/tmp/out" channel="out2"/>
<rmi-source id="rmiSource" channel="in3"/>
<rmi-target id="rmiTarget" local-channel="out3"
remote-channel="someRemoteChannel" host="somehost"/>
<httpinvoker-source name="/some/path" channel="in4"/>
<httpinvoker-target id="httpTarget" channel="out4" url="http://somehost/test"/>
<mail-target id="mailTarget" channel="out5"
host="somehost" username="someuser" password="somepassword"/>
<ws-target id="wsTarget" uri="http://example.org" channel="out6"/>
<ftp-source id="ftpAdapter" channel="in5"
period="60000" host="example.org"
username="someuser" password="somepassword"
local-working-directory="/some/path"
remote-working-directory="/some/path"/>
]]></programlisting>
</para>
</section>
@@ -275,7 +306,7 @@ public class FooService {
public class FooService {
@Handler
public void processFoo(<emphasis>Foo foo</emphasis>) {
public void bar(<emphasis>Foo foo</emphasis>) {
...
}
}</programlisting>
@@ -289,9 +320,20 @@ public class FooService {
<programlisting>@MessageEndpoint(input="exampleChannel", defaultOutput="replyChannel")</programlisting>
</para>
<para>
Finally, just as the 'schedule' sub-element and its 'period' attribute can be provided for a namespace-based
Just as the 'schedule' sub-element and its 'period' attribute can be provided for a namespace-based
endpoint, the 'pollPeriod' attribute can be provided on the <interfacename>@MessageEndpoint</interfacename>.
<programlisting>@MessageEndpoint(input="exampleChannel", pollPeriod=3000)</programlisting>
Likewise, <interfacename>@Concurrency</interfacename> provides an annotation-based equivalent of the
&lt;concurrency/&gt; element:
<programlisting>@MessageEndpoint(input="fooChannel")
@Concurrency(coreSize=5, maxSize=20)
public class FooService {
@Handler
public void bar(Foo foo) {
...
}
}</programlisting>
</para>
<para>
Two additional annotations are supported, and both act as a special form of handler method:

View File

@@ -53,7 +53,7 @@
</row>
<row>
<entry>priority</entry>
<entry>int</entry>
<entry>MessagePriority (an <emphasis>enum</emphasis>)</entry>
</row>
<row>
<entry>properties</entry>
@@ -79,6 +79,17 @@ new GenericMessage&lt;T&gt;(T payload, MessageHeader headerToCopy)</programlisti
<classname>StringMessage</classname> and <classname>ErrorMessage</classname>. The latter accepts any
<classname>Throwable</classname> object as its payload.
</para>
<para>
The <classname>MessagePriority</classname> is only considered when using a <classname>PriorityChannel</classname>
(as described in the next section). It is defined as an <emphasis>enum</emphasis> with five possible values:
<programlisting>public enum MessagePriority {
HIGHEST,
HIGH,
NORMAL,
LOW,
LOWEST
}</programlisting>
</para>
<para>
The <interfacename>Message</interfacename> is obviously a very important part of the API. By encapsulating the
data in a generic wrapper, the messaging system can pass it around without any knowledge of the data's type. As
@@ -200,8 +211,12 @@ new GenericMessage&lt;T&gt;(T payload, MessageHeader headerToCopy)</programlisti
<interfacename>MessageChannels</interfacename> and <interfacename>MessageHandlers</interfacename>. It provides
the following methods:
<programlisting>public void registerChannel(String name, MessageChannel channel)
public void registerHandler(String name, MessageHandler handler, Subscription subscription)
public void registerHandler(String name, MessageHandler handler, Subscription subscription,
public void registerHandler(String name, MessageHandler handler,
Subscription subscription)
public void registerHandler(String name, MessageHandler handler,
Subscription subscription,
ConcurrencyPolicy concurrencyPolicy)</programlisting>
As those method signatures reveal, the message bus is handling several of the concerns here so that the channel
and handler objects can be as simple as possible. These responsibilities include the creation and lifecycle
@@ -292,7 +307,7 @@ public void registerHandler(String name, MessageHandler handler, Subscription su
</table>
The scheduling metadata is provided as an implementation of the <interfacename>Schedule</interfacename>
interface. This is an abstraction designed to allow extensibility of schedulers for messaging tasks. Currently,
there is a single implementation called <classname>PollingSchedule</classname> that provides the following
there is a single implementation named <classname>PollingSchedule</classname> that provides the following
properties:
<table id="api-messagebus-pollingschedule">
<title>Properties of the PollingSchedule</title>
@@ -430,14 +445,15 @@ assertFalse(selector.accept(new GenericMessage<SomeObject>(someObject)));
<programlisting>channel.purge(someSelector);</programlisting>
There is even a <classname>ChannelPurger</classname> utility class whose purge operation is a good candidate for
Spring's JMX support:
<programlisting>ChannelPurger purger = new ChannelPurger(channel, new ExampleMessageSelector());
<programlisting>ChannelPurger purger = new ChannelPurger(new ExampleMessageSelector(), channel);
purger.purge();</programlisting>
</para>
<para>
Implementations of <interfacename>MessageSelector</interfacename> might provide opportunities for reuse on
channels in addition to endpoints. For that reason, Spring Integration provides a simple selector-wrapping
<interfacename>ChannelInterceptor</interfacename> that accepts one or more selectors in its constructor.
<programlisting>MessageSelectingInterceptor interceptor = new MessageSelectingInterceptor(selector1, selector2);
<programlisting>MessageSelectingInterceptor interceptor =
new MessageSelectingInterceptor(selector1, selector2);
channel.addInterceptor(interceptor);</programlisting>
</para>
</section>

View File

@@ -5,8 +5,8 @@
<section id="samples-cafe">
<title>The Cafe Sample</title>
<para>
In this section, we will review a sample application that is included in the Spring Integration Milestone 1
release. This sample is inspired by one of the samples featured in Gregor Hohpe's
In this section, we will review a sample application that is included in the Spring Integration
distribution. This sample is inspired by one of the samples featured in Gregor Hohpe's
<ulink url="http://www.eaipatterns.com/ramblings.html">Ramblings</ulink>.
</para>
<para>
@@ -30,19 +30,18 @@
<para>
Here is the XML configuration:
<programlisting><![CDATA[<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<message-bus/>
<annotation-driven/>
<context:component-scan base-package="org.springframework.integration.samples.cafe"/>
<channel id="orders"/>
@@ -50,13 +49,15 @@
<channel id="coldDrinks"/>
<channel id="hotDrinks"/>
<endpoint input-channel="coldDrinks" handler-ref="barista" handler-method="prepareColdDrink"/>
<endpoint input-channel="hotDrinks" handler-ref="barista" handler-method="prepareHotDrink"/>
<endpoint input-channel="coldDrinks" handler-ref="barista"
handler-method="prepareColdDrink"/>
<endpoint input-channel="hotDrinks" handler-ref="barista"
handler-method="prepareHotDrink"/>
<beans:bean id="cafe" class="org.springframework.integration.samples.cafe.Cafe">
<beans:property name="orderChannel" ref="orders"/>
</beans:bean>
</beans:beans>]]></programlisting>
Notice that the Message Bus is defined. It will automatically detect and register all channels and endpoints.
The 'annotation-driven' element will enable the detection of the splitter and router - both of which carry
@@ -107,7 +108,8 @@ public class Barista {
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("prepared hot drink #" + hotDrinkCounter.incrementAndGet() + ": " + drink);
System.out.println("prepared hot drink #" +
hotDrinkCounter.incrementAndGet() + ": " + drink);
}
public void prepareColdDrink(Drink drink) {
@@ -116,7 +118,8 @@ public class Barista {
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("prepared cold drink #" + coldDrinkCounter.incrementAndGet() + ": " + drink);
System.out.println("prepared cold drink #" +
coldDrinkCounter.incrementAndGet() + ": " + drink);
}
}]]></programlisting>
</para>
@@ -171,7 +174,7 @@ public class Barista {
as described in <xref linkend="namespace-endpoint"/>. Additionally, you can experiment with the channel's
configuration, such as adding a 'dispatcher-policy' as described in <xref linkend="namespace-channel"/>. If you
want to explore the sample in more detail, the source JAR is available in the "dist" directory:
'spring-integration-samples-sources-1.0.0.m1.jar'.
'spring-integration-samples-sources-1.0.0.M3.jar'.
</para>
</section>
</chapter>

View File

@@ -13,7 +13,7 @@
<title>Spring Integration Reference Manual</title>
<productname>Spring Integration</productname>
<releaseinfo>1.0.0.m2 (Milestone 2)</releaseinfo>
<releaseinfo>1.0.0.M3 (Milestone 3)</releaseinfo>
<mediaobject>
<imageobject role="fo">
@@ -31,7 +31,7 @@
</author>
</authorgroup>
<legalnotice>Copyright &copy; SpringSource Inc., 2008</legalnotice>
<legalnotice><para>&copy; SpringSource Inc., 2008</para></legalnotice>
</bookinfo>
<toc></toc>