[jboss-cvs] JBossCache/docs/JBossCache-UserGuide/en/modules ...
Manik Surtani
manik at jboss.org
Mon Apr 23 10:15:07 EDT 2007
User: msurtani
Date: 07/04/23 10:15:07
Modified: docs/JBossCache-UserGuide/en/modules architecture.xml
introduction.xml
Log:
Removed dependency on JBoss Serialization
Revision Changes Path
1.8 +342 -152 JBossCache/docs/JBossCache-UserGuide/en/modules/architecture.xml
(In the diff below, changes in quantity of whitespace are not shown.)
Index: architecture.xml
===================================================================
RCS file: /cvsroot/jboss/JBossCache/docs/JBossCache-UserGuide/en/modules/architecture.xml,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- architecture.xml 30 Jan 2007 19:22:07 -0000 1.7
+++ architecture.xml 23 Apr 2007 14:15:07 -0000 1.8
@@ -5,14 +5,25 @@
<para>
- A <literal>Cache</literal> consists of a collection of <literal>Node</literal> instances, organised in a tree
- structure. Each <literal>Node</literal> contains a <literal>Map</literal> which holds the data
+ A
+ <literal>Cache</literal>
+ consists of a collection of
+ <literal>Node</literal>
+ instances, organised in a tree
+ structure. Each
+ <literal>Node</literal>
+ contains a
+ <literal>Map</literal>
+ which holds the data
objects to be cached. It is important to note that the structure is a mathematical tree, and not a graph; each
- <literal>Node</literal> has one and only one parent, and the root node is denoted by the constant fully qualitied name,
- <literal>Fqn.ROOT</literal>.
+ <literal>Node</literal>
+ has one and only one parent, and the root node is denoted by the constant fully qualitied name,
+ <literal>Fqn.ROOT</literal>
+ .
</para>
<para>
- The reason for organising nodes as such is to improve concurrent access to data and make replication and persistence
+ The reason for organising nodes as such is to improve concurrent access to data and make replication and
+ persistence
more fine-grained.
</para>
<para>
@@ -26,12 +37,18 @@
</mediaobject>
</figure>
- In the diagram above, each box represents a JVM. You see 2 caches in separate JVMs, replicating data to each other.
- These VMs can be located on the same physical machine, or on 2 different machines connected by a network link. The
- underlying group communication between networked nodes is done using <ulink url="http://www.jgroups.org">JGroups</ulink>.
+ In the diagram above, each box represents a JVM. You see 2 caches in separate JVMs, replicating data to each
+ other.
+ These VMs can be located on the same physical machine, or on 2 different machines connected by a network link.
+ The
+ underlying group communication between networked nodes is done using
+ <ulink url="http://www.jgroups.org">JGroups</ulink>
+ .
</para>
- <para>Any modifications (see <link linkend="api">API chapter</link>) in one cache instance will be replicated to
+ <para>Any modifications (see
+ <link linkend="api">API chapter</link>
+ ) in one cache instance will be replicated to
the other cache. Naturally, you can have more than 2 caches in a cluster.
Depending on the transactional settings, this replication will occur either after each modification or at the
end of a transaction, at commit time. When a new cache is created, it can optionally acquire the contents
@@ -42,10 +59,20 @@
<section id="architecture.SPI_interfaces">
<title>SPI Interfaces</title>
<para>
- In addition to <literal>Cache</literal> and <literal>Node</literal> interfaces, JBoss Cache exposes more powerful
- <literal>CacheSPI</literal> and <literal>NodeSPI</literal> interfaces, which offer more control over the internals
+ In addition to
+ <literal>Cache</literal>
+ and
+ <literal>Node</literal>
+ interfaces, JBoss Cache exposes more powerful
+ <literal>CacheSPI</literal>
+ and
+ <literal>NodeSPI</literal>
+ interfaces, which offer more control over the internals
of JBoss Cache. These interfaces are not intended for general use, but are designed for people who wish to
- extend and enhance JBoss Cache, or write custom <literal>Interceptor</literal> or <literal>CacheLoader</literal>
+ extend and enhance JBoss Cache, or write custom
+ <literal>Interceptor</literal>
+ or
+ <literal>CacheLoader</literal>
instances.
</para>
<figure>
@@ -58,16 +85,38 @@
</mediaobject>
</figure>
<para>
- The <literal>CacheSPI</literal> interface cannot be created, but is injected into <literal>Interceptor</literal> and <literal>CacheLoader</literal>
- implementations by the <literal>setCache(CacheSPI cache)</literal> methods on these interfaces. <literal>CacheSPI</literal> extends <literal>Cache</literal>
+ The
+ <literal>CacheSPI</literal>
+ interface cannot be created, but is injected into
+ <literal>Interceptor</literal>
+ and
+ <literal>CacheLoader</literal>
+ implementations by the
+ <literal>setCache(CacheSPI cache)</literal>
+ methods on these interfaces.
+ <literal>CacheSPI</literal>
+ extends
+ <literal>Cache</literal>
so all the functionality of the basic API is made available.
</para>
<para>
- Similarly, a <literal>NodeSPI</literal> interface cannot be created. Instead, one is obtained by performing operations on <literal>CacheSPI</literal>,
- obtained as above. For example, <literal>Cache.getRoot() : Node</literal> is overridden as <literal>CacheSPI.getRoot() : NodeSPI</literal>.
- </para>
- <para>
- It is important to note that directly casting a <literal>Cache</literal> or <literal>Node</literal> to it's SPI
+ Similarly, a
+ <literal>NodeSPI</literal>
+ interface cannot be created. Instead, one is obtained by performing operations on
+ <literal>CacheSPI</literal>
+ ,
+ obtained as above. For example,
+ <literal>Cache.getRoot() : Node</literal>
+ is overridden as
+ <literal>CacheSPI.getRoot() : NodeSPI</literal>
+ .
+ </para>
+ <para>
+ It is important to note that directly casting a
+ <literal>Cache</literal>
+ or
+ <literal>Node</literal>
+ to it's SPI
counterpart is not recommended and is bad practice, since the inheritace of interfaces it is not a contract
that is guaranteed to be upheld moving forward. The exposed public APIs, on the other hand, is guaranteed to
be upheld.
@@ -84,17 +133,30 @@
when the cache is created, based on the configuration used.
</para>
<para>
- It is important to note that the <literal>NodeSPI</literal> offers some methods (such as the <literal>xxxDirect()</literal> method
- family) that operate on a node directly without passing through the interceptor stack. Plugin authors should note
+ It is important to note that the
+ <literal>NodeSPI</literal>
+ offers some methods (such as the
+ <literal>xxxDirect()</literal>
+ method
+ family) that operate on a node directly without passing through the interceptor stack. Plugin authors should
+ note
that using such methods will affect the aspects of the cache that may need to be applied, such as locking,
- replication, etc. Basically, don't use such methods unless you <emphasis>really</emphasis> know what you're doing!
+ replication, etc. Basically, don't use such methods unless you
+ <emphasis>really</emphasis>
+ know what you're doing!
</para>
<section id="architecture.interceptors">
<title>Interceptors</title>
<para>
- An <literal>Interceptor</literal> is an abstract class, several of which comprise an interceptor chain. It
- exposes an <literal>invoke()</literal> method, which must be overridden by implementing classes to add behaviour
- to a call before passing the call down the chain by calling <literal>super.invoke()</literal>.
+ An
+ <literal>Interceptor</literal>
+ is an abstract class, several of which comprise an interceptor chain. It
+ exposes an
+ <literal>invoke()</literal>
+ method, which must be overridden by implementing classes to add behaviour
+ to a call before passing the call down the chain by calling
+ <literal>super.invoke()</literal>
+ .
</para>
<figure>
<title>SPI Interfaces</title>
@@ -106,21 +168,40 @@
</mediaobject>
</figure>
<para>
- JBoss Cache ships with several interceptors, representing different configuration options, some of which are:
+ JBoss Cache ships with several interceptors, representing different configuration options, some of which
+ are:
<itemizedlist>
- <listitem><literal>TxInterceptor</literal> - looks for ongoing transactions and registers with transaction managers to participate in synchronization events</listitem>
- <listitem><literal>ReplicationInterceptor</literal> - replicates state across a cluster using a JGroups channel</listitem>
- <listitem><literal>CacheLoaderInterceptor</literal> - loads data from a persistent store if the data requested is not available in memory</listitem>
+ <listitem>
+ <literal>TxInterceptor</literal>
+ - looks for ongoing transactions and registers with transaction managers to participate in
+ synchronization events
+ </listitem>
+ <listitem>
+ <literal>ReplicationInterceptor</literal>
+ - replicates state across a cluster using a JGroups channel
+ </listitem>
+ <listitem>
+ <literal>CacheLoaderInterceptor</literal>
+ - loads data from a persistent store if the data requested is not available in memory
+ </listitem>
</itemizedlist>
- The interceptor chain configured for your cache instance can be obtained and inspected by calling <literal>CacheSPI.getInterceptorChain()</literal>,
- which returns an ordered <literal>List</literal> of interceptors.
+ The interceptor chain configured for your cache instance can be obtained and inspected by calling
+ <literal>CacheSPI.getInterceptorChain()</literal>
+ ,
+ which returns an ordered
+ <literal>List</literal>
+ of interceptors.
</para>
<section id="architecture.custom_interceptors">
<title>Writing Custom Interceptors</title>
<para>
- Custom interceptors to add specific aspects or features can be written by extending <literal>Interceptor</literal> and overriding
- <literal>invoke()</literal>. The custom interceptor will need to be added to the interceptor chain by using the
- <literal>CacheSPI.addInterceptor()</literal> method.
+ Custom interceptors to add specific aspects or features can be written by extending
+ <literal>Interceptor</literal>
+ and overriding
+ <literal>invoke()</literal>
+ . The custom interceptor will need to be added to the interceptor chain by using the
+ <literal>CacheSPI.addInterceptor()</literal>
+ method.
</para>
<para>
Adding custom interceptors via XML is not supported at this time.
@@ -131,32 +212,58 @@
<section id="architecture.methodcalls">
<title>MethodCalls</title>
<para>
- <literal>org.jboss.cache.marshall.MethodCall</literal> is a class that encapsulates a <literal>java.lang.reflection.Method</literal>
- and an <literal>Object[]</literal> representing the method's arguments. It is an extension of the <literal>org.jgroups.blocks.MethodCall</literal>
+ <literal>org.jboss.cache.marshall.MethodCall</literal>
+ is a class that encapsulates a
+ <literal>java.lang.reflection.Method</literal>
+ and an
+ <literal>Object[]</literal>
+ representing the method's arguments. It is an extension of the
+ <literal>org.jgroups.blocks.MethodCall</literal>
class, that adds a mechanism for identifying known methods using magic numbers and method ids,
which makes marshalling and unmarshalling more efficient and performant.
</para>
<para>
- This is central to the <literal>Interceptor</literal> architecture, and is the only parameter passed in to
- <literal>Interceptor.invoke()</literal>.
+ This is central to the
+ <literal>Interceptor</literal>
+ architecture, and is the only parameter passed in to
+ <literal>Interceptor.invoke()</literal>
+ .
</para>
</section>
<section id="architecture.invocationcontext">
<title>InvocationContexts</title>
<para>
- <literal>InvocationContext</literal> holds intermediate state for the duration of a single invocation, and is set up and
- destroyed by the <literal>InvocationContextInterceptor</literal> which sits at the start of the chain.
+ <literal>InvocationContext</literal>
+ holds intermediate state for the duration of a single invocation, and is set up and
+ destroyed by the
+ <literal>InvocationContextInterceptor</literal>
+ which sits at the start of the chain.
</para>
<para>
- <literal>InvocationContext</literal>, as its name implies, holds contextual information associated with a single cache
+ <literal>InvocationContext</literal>
+ , as its name implies, holds contextual information associated with a single cache
method invocation. Contextual information includes associated
- <literal>javax.transaction.Transaction</literal> or <literal>org.jboss.cache.transaction.GlobalTransaction</literal>,
- method invocation origin (<literal>InvocationContext.isOriginLocal()</literal>) as well as <link
- linkend="configuration.options"><literal>Option</literal> overrides</link>.
- </para>
- <para>
- The <literal>InvocationContext</literal> can be obtained by calling <literal>Cache.getInvocationContext()</literal>.
+ <literal>javax.transaction.Transaction</literal>
+ or
+ <literal>org.jboss.cache.transaction.GlobalTransaction</literal>
+ ,
+ method invocation origin (
+ <literal>InvocationContext.isOriginLocal()</literal>
+ ) as well as
+ <link
+ linkend="configuration.options">
+ <literal>Option</literal>
+ overrides
+ </link>
+ .
+ </para>
+ <para>
+ The
+ <literal>InvocationContext</literal>
+ can be obtained by calling
+ <literal>Cache.getInvocationContext()</literal>
+ .
</para>
</section>
</section>
@@ -164,8 +271,11 @@
<section id="architecture.managers">
<title>Managers For Subsystems</title>
<para>
- Some aspects and functionality is shared by more than a single interceptor. Some of these have been encapsulated
- into managers, for use by various interceptors, and are made available by the <literal>CacheSPI</literal> interface.
+ Some aspects and functionality is shared by more than a single interceptor. Some of these have been
+ encapsulated
+ into managers, for use by various interceptors, and are made available by the
+ <literal>CacheSPI</literal>
+ interface.
</para>
<section id="architecture.rpcmanager">
@@ -187,9 +297,19 @@
<section id="architecture.cacheloadermanager">
<title>CacheLoaderManager</title>
<para>
- Sets up and configures cache loaders. This class wraps individual <literal>CacheLoader</literal> instances
- in delegating classes, such as <literal>SingletonStoreCacheLoader</literal> or <literal>AsyncCacheLoader</literal>,
- or may add the <literal>CacheLoader</literal> to a chain using the <literal>ChainingCacheLoader</literal>.
+ Sets up and configures cache loaders. This class wraps individual
+ <literal>CacheLoader</literal>
+ instances
+ in delegating classes, such as
+ <literal>SingletonStoreCacheLoader</literal>
+ or
+ <literal>AsyncCacheLoader</literal>
+ ,
+ or may add the
+ <literal>CacheLoader</literal>
+ to a chain using the
+ <literal>ChainingCacheLoader</literal>
+ .
</para>
</section>
@@ -198,8 +318,10 @@
<section id="architecture.marshalling">
<title>Marshalling And Wire Formats</title>
<para>
- Early versions of JBoss Cache simply wrote cached data to the network by writing to an <literal>ObjectOutputStream</literal>
- during replication. Over various releases in the JBoss Cache 1.x.x series this approach was gradually deprecated
+ Early versions of JBoss Cache simply wrote cached data to the network by writing to an
+ <literal>ObjectOutputStream</literal>
+ during replication. Over various releases in the JBoss Cache 1.x.x series this approach was gradually
+ deprecated
in favour of a more mature marshalling framework. In the JBoss Cache 2.x.x series, this is the only officially
supported and recommended mechanism for writing objects to datastreams.
</para>
@@ -215,35 +337,68 @@
<section>
<title>The Marshaller Interface</title>
<para>
- The <literal>Marshaller</literal> interface extends <literal>RpcDispatcher.Marshaller</literal> from JGroups.
- This interface has two main implementations - a delegating <literal>VersionAwareMarshaller</literal> and a
- concrete <literal>CacheMarshaller200</literal>.
- </para>
- <para>
- The marshaller can be obtained by calling <literal>CacheSPI.getMarshaller()</literal>, and defaults to the <literal>VersionAwareMarshaller</literal>.
- Users may also write their own marshallers by implementing the <literal>Marshaller</literal> interface and
- adding it to their configuration, by using the <literal>MarshallerClass</literal> configuration attribute.
+ The
+ <literal>Marshaller</literal>
+ interface extends
+ <literal>RpcDispatcher.Marshaller</literal>
+ from JGroups.
+ This interface has two main implementations - a delegating
+ <literal>VersionAwareMarshaller</literal>
+ and a
+ concrete
+ <literal>CacheMarshaller200</literal>
+ .
+ </para>
+ <para>
+ The marshaller can be obtained by calling
+ <literal>CacheSPI.getMarshaller()</literal>
+ , and defaults to the
+ <literal>VersionAwareMarshaller</literal>
+ .
+ Users may also write their own marshallers by implementing the
+ <literal>Marshaller</literal>
+ interface and
+ adding it to their configuration, by using the
+ <literal>MarshallerClass</literal>
+ configuration attribute.
</para>
</section>
<section>
<title>VersionAwareMarshaller</title>
<para>
- As the name suggests, this marshaller adds a version <literal>short</literal> to the start of any stream when
- writing, enabling similar <literal>VersionAwareMarshaller</literal> instances to read the version short and
+ As the name suggests, this marshaller adds a version
+ <literal>short</literal>
+ to the start of any stream when
+ writing, enabling similar
+ <literal>VersionAwareMarshaller</literal>
+ instances to read the version short and
know which specific marshaller implementation to delegate the call to.
- For example, <literal>CacheMarshaller200</literal>, is the marshaller for JBoss Cache 2.0.x.
- JBoss Cache 2.1.x, say, may ship with <literal>CacheMarshaller210</literal> with an improved wire protocol.
- Using a <literal>VersionAwareMarshaller</literal> helps achieve wire protocol compatibility between minor
- releases but still affords us the flexibility to tweak and improve the wire protocol between minor or micro releases.
+ For example,
+ <literal>CacheMarshaller200</literal>
+ , is the marshaller for JBoss Cache 2.0.x.
+ JBoss Cache 2.1.x, say, may ship with
+ <literal>CacheMarshaller210</literal>
+ with an improved wire protocol.
+ Using a
+ <literal>VersionAwareMarshaller</literal>
+ helps achieve wire protocol compatibility between minor
+ releases but still affords us the flexibility to tweak and improve the wire protocol between minor or micro
+ releases.
</para>
<section>
<title>CacheLoaders</title>
<para>
- Some of the existing cache loaders, such as the <literal>JDBCCacheLoader</literal> and the
- <literal>FileCacheLoader</literal> relied on persisting data using <literal>ObjectOutputStream</literal>
- as well, but now, they are using the <literal>VersionAwareMarshaller</literal> to marshall the persisted
+ Some of the existing cache loaders, such as the
+ <literal>JDBCCacheLoader</literal>
+ and the
+ <literal>FileCacheLoader</literal>
+ relied on persisting data using
+ <literal>ObjectOutputStream</literal>
+ as well, but now, they are using the
+ <literal>VersionAwareMarshaller</literal>
+ to marshall the persisted
data to their cache stores.
</para>
</section>
@@ -253,55 +408,90 @@
<section>
<title>CacheMarshaller200</title>
<para>
- This marshaller treats well-known objects that need marshalling - such as <literal>MethodCall</literal>,
- <literal>Fqn</literal>, <literal>DataVersion</literal>, and even some JDK objects such as <literal>String</literal>,
- <literal>List</literal>, <literal>Boolean</literal> and others as types that do not need complete class definitions.
- Instead, each of these well-known types are represented by a <literal>short</literal>, which is a lot more efficient.
+ This marshaller treats well-known objects that need marshalling - such as
+ <literal>MethodCall</literal>
+ ,
+ <literal>Fqn</literal>
+ ,
+ <literal>DataVersion</literal>
+ , and even some JDK objects such as
+ <literal>String</literal>
+ ,
+ <literal>List</literal>
+ ,
+ <literal>Boolean</literal>
+ and others as types that do not need complete class definitions.
+ Instead, each of these well-known types are represented by a
+ <literal>short</literal>
+ , which is a lot more efficient.
</para>
<para>
- In addition, reference counting is done to reduce duplication of writing certain objects multiple times, to help
+ In addition, reference counting is done to reduce duplication of writing certain objects multiple times, to
+ help
keep the streams small and efficient.
</para>
<para>
- Also, if <literal>UseRegionBasedMarshalling</literal> is enabled (disabled by default) the marshaller adds region
- information to the stream before writing any data. This region information is in the form of a <literal>String</literal>
- representation of an <literal>Fqn</literal>. When unmarshalling, the <literal>RegionManager</literal> can be used to
- find the relevant <literal>Region</literal>, and use a region-specific <literal>ClassLoader</literal> to unmarshall
- the stream. This is specifically useful when used to cluster state for application servers, where each deployment has
- it's own <literal>ClassLoader</literal>. See the section below on <link linkend="architecture.regions">regions</link> for more information.
- </para>
- <section>
- <title>JBoss Serialization</title>
- <para>
- Types that the marshaller does not know or care about are serialized using the highly efficient
- <ulink url="http://labs.jboss.com/portal/serialization">JBoss Serialization</ulink> library. This adds
- <literal>jboss-serialization.jar</literal> as a dependency, but can be disabled by adding the following
- JVM argument <literal>-Djboss.serialization=false</literal>. In this case serialization of unknown types
- will fall back to standard Java serialization.
+ Also, if
+ <literal>UseRegionBasedMarshalling</literal>
+ is enabled (disabled by default) the marshaller adds region
+ information to the stream before writing any data. This region information is in the form of a
+ <literal>String</literal>
+ representation of an
+ <literal>Fqn</literal>
+ . When unmarshalling, the
+ <literal>RegionManager</literal>
+ can be used to
+ find the relevant
+ <literal>Region</literal>
+ , and use a region-specific
+ <literal>ClassLoader</literal>
+ to unmarshall
+ the stream. This is specifically useful when used to cluster state for application servers, where each
+ deployment has
+ it's own
+ <literal>ClassLoader</literal>
+ . See the section below on
+ <link linkend="architecture.regions">regions</link>
+ for more information.
</para>
</section>
- </section>
</section>
<section id="architecture.regions">
<title>Class Loading and Regions</title>
<para>
- When used to cluster state of application servers, applications deployed in the application tend to put instances
- of objects specific to their application in the cache (or in an <literal>HttpSession</literal> object) which
- would require replication. It is common for application servers to assign separate <literal>ClassLoader</literal>
+ When used to cluster state of application servers, applications deployed in the application tend to put
+ instances
+ of objects specific to their application in the cache (or in an
+ <literal>HttpSession</literal>
+ object) which
+ would require replication. It is common for application servers to assign separate
+ <literal>ClassLoader</literal>
instances to each application deployed, but have JBoss Cache libraries referenced by the application server's
- <literal>ClassLoader</literal>.
+ <literal>ClassLoader</literal>
+ .
</para>
<para>
To enable us to successfully marshall and unmarshall objects from such class loaders, we use a concept called
regions. A region is a portion of the cache which share a common class loader (a region also has other uses -
- see <link linkend="eviction_policies">eviction policies</link>).
- </para>
- <para>
- A region is created by using the <literal>Cache.getRegion(Fqn fqn, boolean createIfNotExists)</literal> method,
- and returns an implementation of the <literal>Region</literal> interface. Once a region is obtained, a
- class loader for the region can be set or unset, and the region can be activated/deactivated. By default, regions
- are active unless the <literal>InactiveOnStartup</literal> configuration attribute is set to <literal>true</literal>.
+ see
+ <link linkend="eviction_policies">eviction policies</link>
+ ).
+ </para>
+ <para>
+ A region is created by using the
+ <literal>Cache.getRegion(Fqn fqn, boolean createIfNotExists)</literal>
+ method,
+ and returns an implementation of the
+ <literal>Region</literal>
+ interface. Once a region is obtained, a
+ class loader for the region can be set or unset, and the region can be activated/deactivated. By default,
+ regions
+ are active unless the
+ <literal>InactiveOnStartup</literal>
+ configuration attribute is set to
+ <literal>true</literal>
+ .
</para>
</section>
1.8 +4 -8 JBossCache/docs/JBossCache-UserGuide/en/modules/introduction.xml
(In the diff below, changes in quantity of whitespace are not shown.)
Index: introduction.xml
===================================================================
RCS file: /cvsroot/jboss/JBossCache/docs/JBossCache-UserGuide/en/modules/introduction.xml,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- introduction.xml 17 Apr 2007 15:45:04 -0000 1.7
+++ introduction.xml 23 Apr 2007 14:15:07 -0000 1.8
@@ -122,15 +122,11 @@
<para>
In addition to Java 5.0, at a minimum, JBoss Cache has dependencies on
<ulink url="http://www.jgroups.org">JGroups</ulink>
- , Apache's
+ , and Apache's
<ulink
url="http://jakarta.apache.org/commons/logging/">commons-logging
</ulink>
- and
- <ulink url="http://labs.jboss.com/portal/serialization/">JBoss-serialization</ulink>
- for
- performant serialization of objects. JBoss Cache ships with all dependent libraries necessary to run out of the
- box.
+ . JBoss Cache ships with all dependent libraries necessary to run out of the box.
</para>
</section>
@@ -147,4 +143,4 @@
(JBoss Enterprise Middleware Suite).
</para>
</section>
- </chapter>
+</chapter>
More information about the jboss-cvs-commits
mailing list