User: vladimir
Date: 01/02/10 16:55:36
Added: src/docs advconfig.xml basicconfiguration.xml cmp.xml
customizingjaws.xml designnotes.xml howtoejx.xml
howtoj2eedeployer.xml howtojaas.xml
howtojavamail.xml howtojbuilderdebug.xml
howtojca.xml howtojmx.xml howtormhexamples.xml
howtotimer.xml howtotomcat.xml jdbc-database.xml
preface.xml
Log:
iniitial commit of "docbooked" documentatio
Revision Changes Path
1.1 manual/src/docs/advconfig.xml
Index: advconfig.xml
===================================================================
<chapter>
<title>Advanced container configuration</title>
<para>Author:
<author><firstname>Sebastien</firstname><surname>Alborini</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section>
<title>What is jboss.xml?</title>
<para>
To deploy your beans, you have to specify (nearly) everything about them in a
file called ejb-jar.xml.
This file will be stored in the META-INF directory in your ejb-jar file. The
content and syntax of
this file in specified in the ejb1.1 specification (16.5 Deployment descriptor
DTD, pp 244-259).
</para>
<para>
An important point is that the specification does not allow you to add
vendor-specific configuration
in this file. While the ejb-jar.xml is sufficient for most applications, there
may be cases where
you want to add JBoss-specific information in your deployment descriptor. This
can be done by
providing a jboss.xml in the META-INF directory.
</para>
<para>
Note that this file is almost NEVER required by JBoss: JBoss will always
provide a standard behaviour
when no jboss.xml file is found. JBoss does that by first processing a
standardjboss.xml file which
contains the standard configuration.
</para>
<para>
This is what you CAN do in your jboss.xml file:
</para>
<para>
Specifying a particular jndi name for deployment. See the jndi howto
Declare external ejb references. See the ejb-ref howto
Declare resource managers. See the resource manager howto (TBD).
Customize the container configuration for your beans. See the container
configuration howto.
Get all the skinny in gorry details: jboss.xml DTD
</para>
</section>
<section>
<title>Specifying the deployment name of your beans</title>
<para>
You have coded your beans. You now want to deploy them and be
able to access them from your clients.
</para>
<para>
Standard behaviour of jboss
</para>
<para>
The simplest way to deploy your bean is to use the ejb-jar.xml file to give it
the same name you
call it in the client. This is done in the <![CDATA[<ejb-name>]]> tag for the
bean. In this case you DON'T
need a jboss.xml file. Your ejb-jar.xml file will look like this (this is
covered in the beginners trails):
</para>
<para>
ejb-jar.xml:
</para>
<programlisting><![CDATA[
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>MyBeanName</ejb-name>
<home>MyBeanHome</home>
<remote>MyBean</remote>
<ejb-class>MyBeanEJB</ejb-class>
<session-type>Stateful</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
...
</ejb-jar>
]]></programlisting>
<para>
And your bean will be available under the "MyBeanName" in JNDI.
In your client code, your call will look like this:
</para>
<programlisting>
public class Client {
...
public static void main(String arg[]) {
...
//No need to use the "narrow" operation, a cast will work in jboss
MyBeanHome home = (MyBeanHome) new InitialContext().lookup("MyBeanName");
...
}
}
</programlisting>
<para>
Here the "MyBeanName" refers to the name of your bean in the jndi namespace.
JBoss does not currently allow
you to use the java:comp/env namespace to call your beans from your clients.
</para>
<para>
If you want to give a jndi deployment name different than the ejb-name
</para>
<para>
You may want to deploy your bean under another jndi name. (for example, you
may want to deploy the same
bean under different names with different configurations). In this case, you
must specify the jndi name
in a jboss.xml file. This file must be in the META-INF directory, along with
ejb-jar.xml. Your files
will look like this (note that the <![CDATA[<ejb-name>]]>tags in the two xml
files must match):
</para>
<para>
jboss.xml:
</para>
<programlisting><![CDATA[
<jboss>
<enterprise-beans>
<session>
<ejb-name>MyBeanName</ejb-name>
<jndi-name>somePath/otherName</jndi-name>
</session>
</enterprise-beans>
</jboss>
]]></programlisting>
<para>
(you don't need to specify the rest of the jboss.xml file, only this
information is sufficient in the
new metadata, this is what we call "differential" jboss.xml).
</para>
<para>
Your bean is then available in JNDI under somePath/otherName
</para>
<para>
In your client code, your call will look like this:
</para>
<programlisting>
public class Client {
...
public static void main(String arg[]) {
...
//No need to use the "narrow" operation, a cast will work in jboss
MyBeanHome home = (MyBeanHome) new
InitialContext().lookup("somePath/otherName");
...
}
}
</programlisting>
</section>
<section>
<title>Declaring an ejb references</title>
<para>
An ejb reference (see ejb1.1 specification, 14.3, p207) is when a bean A wants
to call methods on a bean B.
We are talking about intra-bean calls also called B2B calls. This is not for
clients (that is covered in
the beginner trails) this is for bean calls all on the server. Most of these
calls are done inside the
server VM.
</para>
<para>
This call will look like this: (beans running on the server must use the
java:comp/env namespace).
</para>
<programlisting>
public class ABean implements EntityBean {
...
public void BusinessMethod(...) {
...
BHome home = (BHome)ctx.lookup("java:comp/env/ejb/myBean");
B bean = home.create(pk);
...
}
}
</programlisting>
<para>
To be allowed this call, the bean A must declare it in the its deployment
descriptor. This is done by an <![CDATA[<ejb-ref>]]>
tag in the bean section of the ejb-jar.xml file. 2 cases may occur:
</para>
<para>
Internal ejb reference: the bean B is in the same application unit as the bean
A. This means that the beans are
physically packaged in the same jar. In this case, you must provide the
<![CDATA[<ejb-link>]]> tag, and its value must
match the <![CDATA[<ejb-name>]]> of bean B. You don't have to provide anything
in the jboss.xml file. Your ejb-jar.xml
file will look like this:
</para>
<programlisting><![CDATA[
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>Bean A</ejb-name>
<home>AHome</home>
<remote>A</remote>
<ejb-class>ABean</ejb-class>
<session-type>Stateful</session-type>
<transaction-type>Container</transaction-type>
<ejb-ref>
<ejb-ref-name>ejb/myBean</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>BHome</home>
<remote>B</remote>
<ejb-link>Bean B</ejb-link>
</ejb-ref>
</session>
<entity>
<ejb-name>Bean B</ejb-name>
<home>BHome</home>
<remote>B</remote>
<ejb-class>BBean</ejb-class>
<persistence-type>Bean</persistence-type>
<prim-key-class>myPK</prim-key-class>
<reentrant>True</reentrant>
</entity>
</enterprise-beans>
...
</ejb-jar>
]]></programlisting>
<para>
External ejb reference: the bean B comes from another application unit, it may
even be deployed on another server.
This means that the beans live in different jars on different systems. In this
case, you cannot rely on the
standard <![CDATA[<ejb-link>]]> tag in ejb-jar.xml since there the beans are
not covered in the same file. Instead, you must
provide the full jndi name of the bean B in jboss.xml. This is necessary to
map the names from different ejb-jar.xml
files since the 2 beans are defined in different application units. A full
name is of the form:
</para>
<para>
protocol://host:1234/name/in/other/server
Note that the <![CDATA[<ejb-ref-name>]]> tags in the 2 xml files must match.
</para>
<para>
ejb-jar.xml:
</para>
<programlisting><![CDATA[
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>Bean A</ejb-name>
<home>AHome</home>
<remote>A</remote>
<ejb-class>ABean</ejb-class>
<session-type>Stateful</session-type>
<transaction-type>Container</transaction-type>
<ejb-ref>
<ejb-ref-name>ejb/myBean</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>BHome</home>
<remote>B</remote>
</ejb-ref>
</session>
</enterprise-beans>
...
</ejb-jar>
]]></programlisting>
<para>
jboss.xml:
</para>
<programlisting><![CDATA[
<jboss>
<enterprise-beans>
<session>
<ejb-name>Bean A</ejb-name>
<ejb-ref>
<ejb-ref-name>ejb/myBean</ejb-ref-name>
<jndi-name>t3://otherserver/application/beanB</jndi-name>
</ejb-ref>
</session>
<enterprise-beans>
</jboss>
]]></programlisting>
<para>
If bean B is deployed in another application, but on the same jboss server,
the jndi-name you provide must be
the name under which bean B is deployed (see the jndi_howto)
</para>
<para>
IMPORTANT NOTE: this will tell jboss where to look for bean B. You also have
to tell jboss what bean B is:
in case of an external ejb-reference, be sure to include bean B's home and
remote interface in bean A's ejb-jar.
</para>
</section>
<section>
<title>Container configuration</title>
<para>
When you deploy an application, JBoss creates a container for each of your
beans. This container will be used
only for this particular bean. It must be configured according to the type of
the bean (CMP Entity Bean, Stateful
Session Bean, etc.). Different standard configurations are stored in the
standardjboss.xml file. You may provide
additional custom configurations in the jboss.xml file for your application.
</para>
<para>
Standard Configurations
</para>
<para>
JBoss currently provides a standard configuration for each type of bean. These
configurations are stored in the
standardjboss.xml file. There are currently 8 standard configurations. If you
don't provide anything else (as we
advise you to do, at least at the beginning), JBoss will automatically choose
the right standard configuration for
your container. The available configurations are the following:
</para>
<para>
Standard CMP EntityBean
Standard BMP EntityBean
Standard Stateless SessionBean
Standard Stateful SessionBean
jdk1.2.2 CMP EntityBean
jdk1.2.2 BMP EntityBean
jdk1.2.2 Stateless SessionBean
jdk1.2.2 Stateful SessionBean
</para>
<para>
The first four ones are used if you run JBoss with a jdk1.3 JVM. The four last
ones are used if you run JBoss with
a jdk1.2.2 JVM.
</para>
<para>
How do I configure my bean for jdk1.2.2 clients ?
If you run JBoss on a jdk1.3 JVM, but your clients use jdk1.2.2, the standard
configuration won't work (the protocols
are not backward compatible). In this case, you have to force JBoss to use the
corresponding jdk1.2.2 configuration.
You do that by providing a jboss.xml file. This file must be in the META-INF
directory of your jar file, along with
ejb-jar.xml. In the section for your bean, simply add a
<![CDATA[<configuration-name>]]> tag. Your xml files will look like
this (note that the <![CDATA[<ejb-name>]]> tags in the 2 xml files must match)
ejb-jar.xml:
</para>
<programlisting><![CDATA[
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>Bean A</ejb-name>
<home>AHome</home>
<remote>A</remote>
<ejb-class>ABean</ejb-class>
<session-type>Stateful</session-type>
<transaction-type>Container</transaction-type>
</ejb-ref>
</session>
</enterprise-beans>
...
</ejb-jar>
]]></programlisting>
<para>
jboss.xml:
</para>
<programlisting><![CDATA[
<jboss>
<enterprise-beans>
<session>
<ejb-name>Bean A</ejb-name>
<configuration-name>jdk1.2.2 Stateful SessionBean<configuration-name>
</session>
<enterprise-beans>
</jboss>
]]></programlisting>
<para>
How do I specify my own custom configuration ?
You may want to provide your own advanced configuration. For example, you may
want to increase the size of your pool,
or use a different instance cache. To do this, you must define your
configuration in jboss.xml in the
<![CDATA[<container-configurations>]]> tag. Then you have to use your new
configuration in the bean section of your jboss.xml file.
For example, if you want to log calls to your bean, your file will look like
this :
</para>
<programlisting><![CDATA[
<jboss>
<enterprise-beans>
<session>
<ejb-name>Bean A</ejb-name>
<configuration-name>Logging Configuration<configuration-name>
</session>
<enterprise-beans>
...
<container-configurations>
<container-configuration>
<container-name>Logging Configuration</container-name>
<call-logging>true</call-logging>
<container-invoker>org.jboss.ejb.plugins.jrmp13.server.JRMPContainerInvoker</container-invoker>
<instance-cache>org.jboss.ejb.plugins.StatefulSessionInstanceCache</instance-cache>
<persistence-manager>org.jboss.ejb.plugins.StatefulSessionFilePersistenceManager</persistence-manager>
<transaction-manager>org.jboss.tm.TxManager</transaction-manager>
<container-invoker-conf>
<Optimized>False</Optimized>
</container-invoker-conf>
</container-configuration>
</container-configurations>
...
</jboss>
]]></programlisting>
<para>
How do I specify advanced cache configuration ?
</para>
<para>
JBoss currently provides the possibility to choose the cache configuration for
each container configuration. You may want
to define your own cache settings, and to do so you must specify them in
jboss.xml under the <![CDATA[<instance-cache>]]> tag and
subtags. Currently 2 cache algorithms have been implemented: a no passivation
cache algorithm (so that all the bean are
kept in memory, unless the bean is an entity bean and you specified for it
commit option C), and a least recently used (LRU)
cache algorithm (so that bean less frequently used are passivated to save
server resources).
</para>
<para>
Let's see how to configure both caches. The examples below are about entity
beans, but the cache settings applies as well
for stateful session beans.For the no passivation cache, jboss.xml will look
like this:
</para>
<programlisting><![CDATA[
<jboss>
<enterprise-beans>
<entity>
<ejb-name>Bean A</ejb-name>
<configuration-name>No Passivation Configuration<configuration-name>
</entity>
<enterprise-beans>
...
<container-configurations>
<container-configuration>
<container-name>No Passivation Configuration</container-name>
...
<instance-cache>org.jboss.ejb.plugins.EntitySessionInstanceCache</instance-cache>
<container-cache-conf>
<cache-policy>org.jboss.ejb.plugins.NoPassivationCachePolicy</cache-policy>
</container-cache-conf>
...
</container-configuration>
</container-configurations>
...
</jboss>
]]></programlisting>
<para>
No further settings are available for the no passivation cache.
For the LRU cache, jboss.xml will look like this:
</para>
<programlisting><![CDATA[
<jboss>
<enterprise-beans>
<entity>
<ejb-name>Bean A</ejb-name>
<configuration-name>LRU Configuration<configuration-name>
</entity>
<enterprise-beans>
...
<container-configurations>
<container-configuration>
<container-name>LRU Configuration</container-name>
...
<instance-cache>org.jboss.ejb.plugins.EntitySessionInstanceCache</instance-cache>
<container-cache-conf>
<cache-policy>org.jboss.ejb.plugins.LRUEnterpriseContextCachePolicy</cache-policy>
<cache-policy-conf>
<min-capacity>5</min-capacity>
<max-capacity>200</max-capacity>
<overager-period>300</overager-period>
<max-bean-age>600</max-bean-age>
<resizer-period>400</resizer-period>
<max-cache-miss-period>60</max-cache-miss-period>
<min-cache-miss-period>1</min-cache-miss-period>
<cache-load-factor>0.75</cache-load-factor>
</cache-policy-conf>
</container-cache-conf>
...
</container-configuration>
</container-configurations>
...
</jboss>
]]></programlisting>
<itemizedlist>
<listitem>
<para><![CDATA[<cache-policy-conf>]]> and its subtags
are optional, so you
can specify none, few or all of them.
<![CDATA[<min-capacity>]]> specifies the minimum capacity of the cache. The
cache can be empty, but will have room for at least
5 beans (in the above case); this value cannot be less than 2; the resizer
(see below) will shrink the cache capacity
down to but not less than this value.
</para>
</listitem>
<listitem>
<para><![CDATA[<max-capacity>]]> specifies the maximum
capacity of the
cache. The cache can be empty, but will have room for at most 200
beans (in the above case); this value cannot be less than the minimum
capacity; the resizer (see below) will enlarge the
cache capacity up to but not more than this value.
</para>
</listitem>
<listitem>
<para><![CDATA[<overager-period>]]> specifies the
period of the overager,
that is a periodic task that runs (in the above case) every 300
seconds. Purpose of this periodic task is to see if in the cache there are
very old beans, and to passivate them.
The age at which a bean is considered too old is also configurable (see
below). While the period of this task is 300 seconds, the first run happens at
a random time between 0 and 300 seconds.
To disable the overager set the period to 0.
</para>
</listitem>
<listitem>
<para><![CDATA[<max-bean-age>]]> specifies the max age
a bean can have
before being passivated by the overager (in this case 600 seconds).
The tag <![CDATA[<resizer-period>]]> specifies the period of the resizer, that
is a periodic task that runs (in the above case) every
400 seconds. Purpose of this periodic task is to shrink / enlarge the cache
capacity upon 3 other parameters (see below).
While the period of this task is 400 seconds, the first run happens at a
random time between 0 and 400 seconds.
To disable the resizer set the period to 0.
</para>
</listitem>
<listitem>
<para><![CDATA[<max-cache-miss-period>]]>,<![CDATA[<min-cache-miss-period>]]>
and <![CDATA[<cache-load-factor>]]> control the resizer in this way: the
number of
cache misses is internally recorded. When the resizer runs, it sees what is
the cache miss rate from the last time it ran.
If there is more than (in the above case) one cache miss every 1 second
(min-cache-miss-period) then the resizer tries to
enlarge the cache; if there is less than (in this case) one cache miss every
60 seconds (max-cache-miss-period) then the
resizer tries to shrink the cache. How much is the cache enlarged / shrinked ?
Here is where the load-factor comes in the
picture. When the resizer shrinks, it tries to shrink the cache so that (in
this case) the ratio number of beans / cache
capacity is 0.75; when the resizer enlarges, it tries to enlarge the cache by
a factor 1 / 0.75 == 1.333 (in the above case) plus a correction calculated
from the cache miss rate (so that the more cache miss rate you have, the more
the cache is enlarged, starting from at least 1.333; so if you really have a
lot of cache misses, the resizer may decide to enlarge the cache of a factor
2.0 instead of 1.333 - if there is room for that).
</para>
</listitem>
</itemizedlist>
<para>
What can be configured ?
</para>
<para>
These are the different things you can customize in a
<![CDATA[<container-configuration>]]> tag in jboss.xml. See the jboss.xml DTD
for
more details:
</para>
<itemizedlist>
<listitem>
<para><![CDATA[<call-logging>]]> this tag must have a boolean
value: true
or false. It tells the container if calls to this bean must be
logged or not. It is set to false in standard configurations.
</para>
</listitem>
<listitem>
<para><![CDATA[<container-invoker>]]> the container invoker.
</para>
</listitem>
<listitem>
<para><![CDATA[<instance-pool>]]> the instance pool is a set
(a "pool") of
free (ie not currently associated to a context) instances of the
bean. When an instance of the bean is no longer used, it is thrown back to the
pool. This is not used for Stateful Session
Beans, since the instances are not reusable.
</para>
</listitem>
<listitem>
<para><![CDATA[<instance-cache>]]> the cache contains the
instances of a
bean which are currently associated to a context. If it grows too
big, the cache may decide to passivate some of the instances. This is not used
for Stateless Session Beans, since these
are directly reusable after a call.
</para>
</listitem>
<listitem>
<para><![CDATA[<persistence-manager>]]> the persistence
manager is in
charge of storing permanent information in the instance of a bean.
For BMP Entities, it will merely transmit orders to the bean; for Stateful
Sessions and CMP Entities, it has to save the
state of the bean. This is not used for Stateless Session Beans, since they
don't have a state to save.
</para>
</listitem>
<listitem>
<para><![CDATA[<container-invoker-conf>]]> configuration of
the container
invoker.
</para>
</listitem>
<listitem>
<para><![CDATA[<container-cache-conf>]]> configuration of the
cache. For
example, you may specify the time interval between passivations.
</para>
</listitem>
<listitem>
<para><![CDATA[<container-pool-conf>]]> configuration of the
pool. Mainly,
the size of the pool.
</para>
</listitem>
<listitem>
<para><![CDATA[<commit-option>]]> must be A, B or C. See the
ejb
specification for more details.
</para>
</listitem>
</itemizedlist>
</section>
</chapter>
1.1 manual/src/docs/basicconfiguration.xml
Index: basicconfiguration.xml
===================================================================
<chapter><title>Basic configuration</title>
<para>Author:
<author><firstname>Aaron</firstname><surname>Mulder</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section><title>In a nutshell</title>
<para>
JBoss ships preconfigured, so there's nothing you need to do to get it up and
running with the test beans. However, you
will likely need to make minor configuration changes to support your specific
applications. This section gives an
overview of the configuration files and directories. The Advanced Configuration
section gives detailed instructions for
specific configuration changes you may require. The Appendix contains DTDs for the
configuration files, which gives the
exact information.</para>
<section><title>Important Directories</title>
<para>
The directory names given here are all relative to the directory you installed JBoss
into.</para>
</section>
<section><title>Executables</title>
<para>
Executables are located in the bin directory. Using the Batch (Windows) or Shell
(UNIX) scripts here, you can start the
server or run the test bean client. You can also run the EJX deployment descriptor
editor by double-clicking on it (if
your platform supports that) or issuing the command:
<command>
java -jar ejx.jar
</command>
</para>
</section>
<section><title>Configuration</title>
<para>
Configuration files are located in the conf directory. These files configure the
server as a whole, so the settings here will
be the same for all EJBs.</para>
</section>
<section><title>Libraries</title>
<para>
Java libraries are located in the lib directory. They should use either the ZIP or
JAR format. All libraries in this directory
will automatically be added to the server classpath. Again, this should only be used
for libraries which need to be
available to all EJBs; there are alternatives for libraries that should be available
to individual EJB JARs (see The
Manifest File in the Deploying EJBs in jBoss section).</para>
</section>
<section><title>EJBs</title>
<para>
EJB JARs you want to deploy go in the deploy directory. If the server is running,
they will be deployed automatically. If
you delete a JAR it will be undeployed, and if you update it it will be
redeployed.</para>
</section>
<section><title>Client Libraries</title>
<para>
Libraries required for clients are in the client directory. A typical client
requires jboss-client.jar,
jnp-client.jar, ejb.jar, and jta-spec1_0_1.jar. If you client is not running JDK
1.3, it will require
jndi.jar as well.</para>
</section>
<section><title>Configuration Files</title>
<para>
There are a number of configuration files for jBoss. The contents of each are give
here, though you should refer to the
Advanced Configuration section and the DTDs section of the Appendix for details on
the specific settings.</para>
<para>
You may create more than one set of configuration files as long as the base filename
is the same for all files in the set
and the extensions are not changed. For example, you could copy jboss.conf,
jboss.jcml, ... to
myconfig.conf, myconfig.jcml, ... To start jboss with a different set of
configuration files, add the base name
of the configuration file set to the command or script you use to start jBoss (for
example, "run.sh myconfig").</para>
<table><title>Configuration files</title>
<tgroup cols="2">
<thead>
<row>
<entry>File</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>jboss.conf</entry>
<entry>Lists server components that should be loaded. Each must be a JMX
MBean</entry>
</row>
<row>
<entry>jboss.jcml</entry>
<entry>Lists configuration parameters for the server components loaded in
jboss.conf</entry>
</row>
<row>
<entry>jboss.properties</entry>
<entry>Provides parameters to the Java runtime (the entries here become
system properties)</entry>
</row>
<row>
<entry>jboss.dependencies</entry>
<entry>Lists dependencies between the MBeans loaded in jboss.conf, so they
can be loaded and
stopped in the correct order</entry>
</row>
<row>
<entry>jnp.properties</entry>
<entry>Lists properties for the JNDI server implementation</entry>
</row>
<row>
<entry>jndi.properties</entry>
<entry>Lists properties for the JNDI client implementation. You can achieve
the same thing by
hardcoding the properties, passing them on the command line, or
putting this file on the client
classpath. We recommend putting this on the classpath since it is
easiest to use and easiest to
change. You have to hardcode the properties if you want to look up
beans on more than one
server, though.</entry>
</row>
<row>
<entry>server.policy</entry>
<entry>The default security policy for the jBoss server. Currently, this is
set to allow all permissions. In
a future release it will be locked down more.</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section><title>Clients on Remote Machines</title>
<para>
The default configuration assumes client will run on the same machine as the jBoss
server. While often appropriate for
servlet and JSP clients, you need to make minor changes to support remote
clients.</para>
<orderedlist>
<listitem><para>Change jboss.properties. The properties
java.rmi.server.useLocalHostName and
java.rmi.server.hostname should either both be commented out, or
useLocalHostName should be
set to true and hostname should be set to the host name of your server (the
name you want your clients to
use, if your server has more than one). </para></listitem>
<listitem><para>Set the JNDI properties for your clients appropriately. If you
choose to put jndi.properties on the client classpath
(which is recommended), you should change the value for
java.naming.provider.url to the host
name of your server (again, the name you want your clients to use).
</para></listitem>
</orderedlist>
</section>
</section>
</chapter>
1.1 manual/src/docs/cmp.xml
Index: cmp.xml
===================================================================
<chapter>
<title>Using container-managed persistence</title>
<para>Author:
<author><firstname>Kevin</firstname><surname>Boone</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section><title>Introduction</title>
<section><title>What this article is about</title>
<para>
This article presensts a step-by-step example of creating, deploying and
testing an Entity JavaBean that uses
`container-managed persistence' with the JBoss EJB server. This
example is very simple, and is a variation of
the old favourite `music CD' case study. I have chosen this example
because the application is likely to be
familiar to most people without much explanation. In short, the `CD'
EJB models a music CD. Applications
will want to add and delete CDs to a collection, and search the collection
for specific CDs. There is also a
`CDCollection' EJB that lists and searches collections of CDs.</para>
<para>
The full source code to accompany this article can be found here (in
gzipped tar format). This archive
contains the Java source code, JavaDoc documentation, and a text file of test
data (CDs.txt) to initialize the
database.</para>
<para>
Although I will occasionally make reference to Linux, this is only because
that's what I use for EJB
development; most of the material in this article will work with any Unix
version, and even with Windows NT
if the directory structure is adjusted accordingly.</para>
</section>
<section><title>Pre-requisites</title>
<para>
You will need a fully-functioning JBoss installation to follow this tutorial,
which must have a working
database connection. I will assume that you are basically familiar with EJBs
and know how to structure and
compile JavaBeans as Java packages. Also I will assume you know the basic
structure of a deployment
descriptor, and the run-time descriptor that JBoss uses (jboss.xml). I will
assume that you know how to
package and deploy EJBs using JBoss. If you don't know about these things, you
might want to look at my
introductory article on JBoss first.</para>
</section>
<section><title>JBoss hints</title>
<para>JBoss is written entirely in Java, as is the `Hypersonic' database with
which it is supplied. Searching a database
requires lots of repetitive operations, and an interpreting Java system will
be extremely slow if the database is
large. If you are using the Sun JDK, you will need to ensure that it is
configured to use the `Hotspot' virtual
machine, to achieve anything close to acceptable performance. For the purposes
of study, you could get along
by ensuring that the database size is kept small, but with even a hundred
objects you will find it too slow to use.
Some Linux systems are reluctant to use the `Hotspot' JVM, but they can
normally be coerced to.</para>
</section>
<section><title>Persistence: review</title>
<para>
There are, in essence, two kinds of Enterprise JavaBean: session and entity.
Entity EJBs contain information
that is persistent across different client-Bean interactions, while session
EJBs don't. For example, a class
called `Customer' that represents the customers of a particular service will
contain persistent information
(about the customer). A class called `CustomerFinder', say, that finds
Customer instances that match certain
criteria is likely to be a session EJB, because it does not require
information that is maintained between
different client-server interactions.</para>
<para>
Session EJBs can be further divided into `stateless' and `stateful'. A
stateful session EJB has a state that is
persistent between invocations of its methods. A stateless EJB does not even
have to retain its state between
method invocations. The stateless session EJB is therefore the type of EJB
that exhibits the least persistence.</para>
<para>
The entity EJBs contain information that persists even when no clients
are using any of the Bean's
services; the information should persist even if the server is restarted.
There is a high degree of
correspondence between instances of an entity EJB and rows of a database
table. In practice, all EJB servers
implement entity instances as table rows. This correspondence is so strong
that the notion of a `primary key'
is relevant to an entity EJB. Of course, a primary key is a database concept,
not an object-orientation concept
at all.</para>
<para>
The persistence of an entity EJB may be managed by the Bean itself, or
by the server (technically by the
`container'). The latter technique is called `Container-managed persistence',
and is the subject of the rest of
this article.</para>
</section>
<section><title>When to Use CMP or BMP?</title>
<para>
Unlike what many folks believe, the choice of going BMP or CMP is not really
one of "trade-off". If you have
already schemas deployed you may find that the complexity of the schemas
requires you to go with BMP or use
a BMP generating tool such as "cocobase". These techniques are what we call
"fake CMP" where the work of
accessing the database is left to the generated classes. </para>
<para>
The breed of CMP that has most value is the "real CMP" or a CMP where you let
the container manage the
persistent representation of your beans entirerly. This might not work right
now for you if your object are
complex but should work in most simple cases. EJB2.0 also goes the extra
length to make the persistent
engines powerful and fast with management of dependencies and relationships.
We believe that one day you
will rely on the engines to manage the schemas, just like you rely on a
compiler to optimize assembly code.</para>
</section>
</section>
<section><title>Container Managed Persistence - CMP</title>
<section>
<title>Determine the persistent classes</title>
<para>
In this simple example we will use two Enterprise JavaBeans. The first, called
`CD' models a music CD.
It contains attributes (instance variables) that store the title ID code and
various other
properties of a music CD. The second is called `CDCollection', and models a
collection of such CDs.
This bean acts as a simple interface between the client and the CD Bean;
technically we could
manage without it but it does make certain operations easy to follow. The
CDCollection Bean
will have the following methods deleteAll(), addCd(), findInAnyField() and
findAll().
</para>
<para>
<itemizedlist>
<listitem><para>
addCd() - Adds a single CD specified by values of its
attributes</para></listitem>
<listitem><para>
deleteAll() - Delete all CDs </para></listitem>
<listitem><para>findInAnyField() - Returns an array of CD instances
which have
the specified text string in any of their
attributes</para></listitem>
<listitem><para>
findAll() - Returns an array of all CD instances in the system
</para>
</listitem>
</itemizedlist>
</para>
<para>
All these methods could be implemented by direct manipulation of the home
interface of the CD Bean,
but it is slightly more elegant to do it this way.
</para>
<para>
Because the CDCollection Bean only interacts with the CD Beans during requests
from clients, it
appears to have no persistent information. So it is a session Bean. Moreover,
since each method
is completely self-contained, it is a stateless session bean.
</para>
<para>
The CD Bean, however, will be an entity EJB because some of its information is
persistent.
For example, the ID, artist, title, type and notes about the recording will
all be persistent.
Of course the CD Bean may have other instance variables, but they won't
necessarily be persistent.
For example, some will hold temporary data, and others will be derived from
the persistent attributes.
</para>
<para>
In this example, I will assume that the persistent fields are all Java
`String' values representing
the ID, title, artist, type and notes. You could, of course, add other
information you feel to be
important.
</para>
</section>
</section>
<section>
<title>Creating the Beans</title>
<para>
The entity bean representing the CD is very easy to code, as it doesn't have
to do a great deal.
All the issues of persistence will be taken care of by the server. I will
present the full code
for this Bean below; the code for the CDCollection Bean will not be discussed
further because it
is not interesting in the context of container-managed persistence. Remember
that the full source
code is available to download: click here.
</para>
<para>
CD.java: remote interface for the `CD' Bean
</para>
<para>
<programlisting>
package com.web_tomorrow.cd;
import java.rmi.RemoteException;
import javax.ejb.*;
/**
This interface defines the remote interface to the `CD' EJB
*/
public interface CD extends EJBObject
{
/**
Get CD title
*/
public abstract String getTitle() throws RemoteException;
/**
Set CD title
*/
public abstract void setTitle(String title) throws RemoteException;
/**
Set CD ID code
*/
public abstract String getId() throws RemoteException;
/**
Get CD ID code
*/
public abstract void setId(String id) throws RemoteException;
/**
Get artist
*/
public abstract String getArtist() throws RemoteException;
/**
Set artist
*/
public abstract void setArtist(String artist) throws RemoteException;
/**
Get type (rock, classical, chamber music, etc)
*/
public abstract String getType() throws RemoteException;
/**
Set type
*/
public abstract void setType(String type) throws RemoteException;
/**
Get notes (comments, not musical notes!)
*/
public abstract String getNotes() throws RemoteException;
/**
Set notes
*/
public abstract void setNotes(String type) throws RemoteException;
}
</programlisting>
</para>
<para>
The remote interface specifies methods to get and set the attributes of the
object.
That's all it needs to do in this example. Note that, as with any Java Bean,
the
names of these methods must follow the standard convention; that is, if an
attribute
is called `String X' then the `get' and `set' methods must be defined as
follows:
</para>
<programlisting>
String getX();
void setX(String);
</programlisting>
<para>
Note also that JBoss requires that these methods are declared as `abstract'
when using CMP.
It does not matter for session Beans, and some EJB server aren't fussy (e.g.,
Sun J2EE), but
with CMP in JBoss you need to say `abstract'. Failure to do so will result in
the following
error message during deployment:
</para>
<literallayout>
<computeroutput>
[Container factory] org.jboss.ejb.DeploymentException: Could not find matching
method for public abstract java.lang.String somepackage.getSomeField()
throws java.rmi.RemoteException, Cause:java.lang.NoSuchMethodException:
getSomeField()
</computeroutput>
</literallayout>
<para>
CDHome.java: home interface for the `CD' Bean
</para>
<programlisting>
package com.web_tomorrow.cd;
import java.rmi.RemoteException;
import javax.ejb.*;
import java.util.Collection;
/**
This interface defines the home interface for the `CD' EJB
*/
public interface CDHome extends EJBHome
{
/**
Create a new CD instance
*/
public CD create(String id) throws RemoteException, CreateException;
/**
Find the CD with the specified ID. This method is not implemeted by the Bean,
but by the container
*/
public CD findByPrimaryKey (String id) throws RemoteException,
FinderException;
/**
Finds the CD whose `type' attribute matches that specified. This method is
implemented by the container
*/
public Collection findByType (String type) throws RemoteException,
FinderException;
/**
Get all CD instances. This method is
implemented by the container
*/
public Collection findAll() throws RemoteException, FinderException;
}
</programlisting>
<para>
The important thing to note about this interface is that it specifies methods
that
don't need to be implemented. In this case, findByPrimaryKey(), findByType()
and findAll()
are all examples of `finder' methods. The EJB specification requires that the
server be able
to provide finder methods for all the persistent attributes in the object. So,
for example,
if your class has an attribute `X', then the server will provide a `findByX'
method to search
on that field. Note that with JBoss the search is `exact'; that is, it won't
accept wild-card
characters or an incorrect mixture of upper- and lower-case letters. The
findByPrimaryKey()
searches on the primary key field; we will discuss how the primary key is
specified later.
</para>
<para>
CDBean.java: implementation of the `CD' Bean
</para>
<para>
<programlisting>
package com.web_tomorrow.cd;
import java.rmi.RemoteException;
import javax.ejb.*;
/**
This class contains the implementation for the methods specified in the home
and remote interfaces for the `CD' EJB
*/
public class CDBean implements EntityBean
{
transient private EntityContext ctx;
public String id;
public String title;
public String artist;
public String type;
public String notes;
/**
Create an instance of a CD. Note that this method returns null because the real
creation is managed by the EJB container.
*/
public String ejbCreate (String _id)
{
id = _id;
return null;
}
/**
Called when the object has been instantiated; does nothing in this example
*/
public void ejbPostCreate(String id) { }
public String getTitle() { return title; }
public void setTitle(String _title) { title = _title; }
public String getId() { return id; }
public void setId(String _id) { id = _id; }
public String getArtist() { return artist; }
public void setArtist(String _artist) { artist = _artist; }
public String getType() { return type; }
public void setType(String _type) { type = _type; }
public String getNotes() { return notes; }
public void setNotes(String _notes) { notes = _notes; }
public void setEntityContext(EntityContext ctx) { this.ctx = ctx; }
public void unsetEntityContext() { ctx = null; }
public void ejbActivate() { }
public void ejbPassivate() { }
public void ejbLoad() { }
public void ejbStore() { }
public void ejbRemove() { }
}
</programlisting>
</para>
<para>
The CDBean class provides implementations of the methods that aren't provided
automatically
by the EJB container. Note that the ejbCreate method returns `null', meaning
that the
container should take care of initializing the instance in the server's
process space.
Because the CD Bean is essentially passive -- a data repository -- it only has
a few methods.
These classes (and the CDCollection classes) can be compiled in the usual way;
don't forget
to include the path to the JBoss EJB class library in your classpath, e.g.,
</para>
<para>
<command>
javac -classpath /usr/lib/jboss/lib/ext/ejb.jar:. ....
</command>
</para>
</section>
<section>
<title>Packaging and deploying the Beans</title>
<para>
Deploying an entity bean requires providing some extra information, in
addition to that required
for a session bean. This information is provided in the deployment descriptor
ejb-jar.xml
</para>
<programlisting><![CDATA[
<enterprise-beans>
<entity>
<description>Models a music CD</description>
<ejb-name>CDBean</ejb-name>
<home>com.web_tomorrow.cd.CDHome</home>
<remote>com.web_tomorrow.cd.CD</remote>
<ejb-class>com.web_tomorrow.cd.CDBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>
<cmp-field><field-name>id</field-name></cmp-field>
<cmp-field><field-name>title</field-name></cmp-field>
<cmp-field><field-name>artist</field-name></cmp-field>
<cmp-field><field-name>type</field-name></cmp-field>
<cmp-field><field-name>notes</field-name></cmp-field>
<primkey-field>id</primkey-field>
</entity>
<!-- more beans here -->
</enterprise-beans>
]]></programlisting>
<para>
The listing above shows the section of ejb-jar.xml that is relevant to the CD
Bean. It has the
usual information about the classes that consitute the Bean, but it also
specifies the type
and name of the primary key, and the fields that are persistent. Note that in
this case the
`id' field gets listed twice: once as a persistent field and then again as the
primary key field.
It might be thought that specifying a field as a primary key would
automatically make it persistent,
but it doesn't. Leaving out thecmp-field definition for the primary key
results in this error
message at deployment time:
</para>
<para>
<computeroutput>
[JAWS] Initializing JAWS plugin for CDBean
[Container factory] java.lang.NoSuchFieldException: CASE_INSENSITIVE_ORDER
</computeroutput>
</para>
<para>
The deployment descriptor for the CDCollection class does not require any
persistence information,
but it does require an ejb-ref section; this indicates that the CDCollection
Bean refers to CD Bean
instances. The ejb-ref section lists the type of the CD Bean, and all its
classes.
</para>
<programlisting><![CDATA[
<session>
<description>Models a music CD collection</description>
<ejb-name>CDCollectionBean</ejb-name>
<home>com.web_tomorrow.cd.CDCollectionHome</home>
<remote>com.web_tomorrow.cd.CDCollection</remote>
<ejb-class>com.web_tomorrow.cd.CDCollectionBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<ejb-ref>
<ejb-ref-name>ejb/CD</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>com.web_tomorrow.cd.CDHome</home>
<remote>com.web_tomorrow.cd.CD</remote>
<ejb-link>com.web_tomorrow.cd.CDBean</ejb-link>
</ejb-ref>
</session>
]]></programlisting>
<para>
In the JBoss run-time configuration file `jboss.xml' we should specify the
JNDI names of the
Beans, like this:
</para>
<programlisting><![CDATA[
<entity>
<ejb-name>CDBean</ejb-name>
<jndi-name>cd/CD</jndi-name>
</entity>
<session>
<ejb-name>CDCollectionBean</ejb-name>
<jndi-name>cd/CDCollection</jndi-name>
</session>
]]></programlisting>
<para>
This says the `CDBean' has the JNDI name `cd/CD' and `CDCollectionBean' has
the JNDI name `cd/CDCollection'.
Note that the method of specifying these JNDI names depends on the server.
</para>
<para>
When packaging these Beans, don't forget to include the files ejb-jar.xml and
jboss.jar in the
directory META-INF.During deployment (simply copy the packaged beans to the
`deploy' subdirectory
of the JBoss directory) you should see a message like the following:
</para>
<literallayout>
<computeroutput>
[Container factory] Deploying:file:/usr/lib/jboss/deploy/cd.jar
[Container factory] Deploying CDBean
[Container factory] Deploying CDCollectionBean
[JAWS] Initializing JAWS plugin for CDBean
[JAWS] Remove:DELETE FROM CDBean WHERE id=?
[JAWS] Drop:DROP TABLE CDBean
[JAWS] Create table:CREATE TABLE CDBean (notes VARCHAR(256),title
VARCHAR(256),artist VARCHAR(256),id VARCHAR(256),type VARCHAR(256))
[JAWS] Insert:INSERT INTO CDBean (notes,title,artist,id,type) VALUES
(?,?,?,?,?)
[JAWS] Select:SELECT notes,title,artist,id,type FROM CDBean WHERE id=?
[JAWS] Table CDBean exists
[Container factory] Started: CDBean
[Container factory] Bind ejb/CD to com.web_tomorrow.cd.CDBean
[Container factory] Started: CDCollectionBean
[Container factory] Bound CDBean to cd/CD
[Container factory] Bound CDCollectionBean to cd/CDCollection
[Container factory] Deployed application: file:/usr/lib/jboss/deploy/cd.jar
</computeroutput>
</literallayout>
<para>
`JAWS' is the JBoss interface to the database engine. During deployment JAWS
has
deleted any existing table called `CDBean', then created a new CDBean table
with
the specified column layout. How does it know to use VARCHAR(256) for each
field?
It doesn't: it's guessing because we haven't provided any other information.
During deployment, JAWS looks for a file called `jaws.xml'; if this file
exists
it is read to configure the names and geometry of the database tables.
VARCHAR(256) is the default for String attributes. The default table name is
the
same as that of the Bean class, which is why we have ended up with a table
called
`CDBean'. This also can be over-ridden in jaws.xml. In practice, the JAWS
defaults
are adequate for most applications. However, there may be speed advantages to
using fixed-length fields (e.g., CHAR(XX) rather than variable-length ones if
at
all possible.
</para>
<para>
Note that it can be very difficult to change the number or names of columns
in the table once there is data in it. JBoss gets very confused by this, as
you
would expect. When a CMP Bean is re-deployed, JAWS tries to write into its
table
all the data it had in its last deployment. If the table has different columns
it probably won't be able to do that. This means that it is important to get
the
persistent fields thoroughly correct before starting to put real data into the
application.
</para>
</section>
<section>
<title>Creating a test client </title>
<para>
Client for EJBs may be any Java program or applet; in this simple example I
will describe
a very simple client program that can be run from the command line. It simply
dumps the
attributes of all the CD Beans to standard output. The source code also
provides clients
for searching and uploading to the database, all operating at the command line.
</para>
<para>
The client does not interact directly with CD instances, it uses the
CDCollection bean
as a mediator. CDCollection is a stateless session bean. In this example, the
client
calls the `findAll' method to get references to all the CD objects currently
in the
system. To run this client, you will first need to get some CD objects
created. You
can use the `Upload' client for this, to create CD instances from a text file.
</para>
<para>
To avoid the necessity to specify the URL of the Bean server in the client
source code,
this client reads the required information from a properties file called
`cd.properties'.
The file should contain the URL and driver for the naming service, like this:
</para>
<para>
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost:1099
</para>
<para>
Of course, if your server and client are on different computers, you will need
to
change `localhost' to the real location of the server.
</para>
<para>
Here is the full listing of the `List' client.
</para>
<programlisting><![CDATA[
package com.web_tomorrow.cd;
import javax.naming.*;
import java.util.Hashtable;
import javax.rmi.PortableRemoteObject;
import java.util.Properties;
import java.io.FileInputStream;
/**
This is a simple client for the `CD' EJB; it lists (to standard output) all
the `CD' instances in
the system. The `main' method allows this class to be run from the command
line.
*/
class List
{
public static void main(String[] args)
{
// Get information about the Bean server from the properties file
Properties props = new Properties();
Properties sysProps = System.getProperties();
try
{
props.load (new FileInputStream ("cd.properties"));
sysProps.putAll(props);
}
catch (Exception e)
{
System.err.println ("Can't read `cd.proprties'");
System.exit (-1);
}
System.setProperties (sysProps);
// Enclosing the whole process in a single `try' block is not an ideal way
// to do exception handling, but I don't want to clutter the program up
// with catch blocks
try
{
// Get a naming context
InitialContext jndiContext = new InitialContext();
// Get a reference to a CD Bean
Object ref = jndiContext.lookup("cd/CDCollection");
// Get a reference from this to the Bean's Home interface
CDCollectionHome home = (CDCollectionHome)
PortableRemoteObject.narrow (ref, CDCollectionHome.class);
CDCollection cdCollection = home.create();
CD[] cds = cdCollection.findAll();
for (int i = 0; i < cds.length; i++)
{
System.out.println (cds[i].getId() + "\t" + cds[i].getTitle() + "\t" +
cds[i].getArtist() + "\t" + cds[i].getType());
}
}
catch(Exception e)
{
System.out.println(e.toString());
}
}
}
]]></programlisting>
<para>
To run this client you will need to specify in the CLASSPATH the location the
JBoss client libraries, so the command line will be like this:
</para>
<para>
<command>
java -classpath
$CLASSPATH:/usr/lib/jboss/lib/ext/ejb.jar:/usr/lib/jboss/client/jboss-client.jar
\
com.web_tomorrow.cd.List;
</command>
</para>
<para>
If all is well, you will get a list of CDs.So we've created an entity EJB, and
a client
program that uses it.You'll agree, I hope, that it isn't that much more
complicated than
creating a session EJB. The additional steps required are:
</para>
<para>
The ejb-jar.xml file needs to indicate that the object is persistent, and list
the persistent fields.
It also needs to specify the name and class of the primary key field.
</para>
<para>
If the default column names and types aren't what you need, create a file
jaws.xml to specify them.
</para>
</section>
<section><title>Discussion: container-managed persistence</title>
<para>
If you followed the tutorial on container-managed persistence with JBoss,
you will have seen that creating persistent, distributed objects is not
really any more difficult than creating transient ones. The EJB container does
most of the hard work; all the programmer needs to do is to tell it
which fields are persistent. However, it isn't quite as simple as that, and
naive use of CMP can lead to very inefficient programs. To see why,
it's necessary to understand at least in outline how the EJB server deals with
container-managed persistence.
</para>
<section>
<title>Technical overview </title>
<para>
In the EJB field there is a very strong correspondence between `rows of a
database table', and `instances of an object'. It is clear that the EJB
developers had this notion in mind from the very beginning. While the
specification doesn't stipulate that persistence is provided by database
tables, in practice it always is. Moreover, it is tacitly assumed that the
communication between the Beans and the database will be by means of
SQL statements. What does this imply for container-managed persistence?
</para>
<para>
When an persistent object is instantiated, the EJB container must
generate SQL code that will write a row in the table. When the object is
deleted, it must generate SQL to remove it. This isn't much of a problem. When
one object asks for a reference to another, the container must
find (or create) that object's row in the table, read the columns, instantiate
the object in the JVM, and write the data from the table into its
instance variables. Because this process can be quite slow, the EJB server may
choose to defer it. That is, when one object gets a reference to
an object that is container-managed, the latter object may be uninitialized.
Initialization from the database table takes place later, perhaps
when one of the methods is called. This late initialization reduces
inefficiencies arising from initializing objects that are never read, but has
its own problems, as we shall see. </para>
</section>
<section><title>Limitations of CMP </title>
<section><title>Efficiency limitations </title>
<para>
The main limitation is that the EJB container will probably not be able to
generate database access statements with the efficiency of a human
programmer. Consider this example: suppose I have an database table containing
details of my music CD collection. I want to search ithe
collection for any one which has the text `Chopin' (case insensitive) in
either the `title' or `notes' column. In SQL I could write a statement like
this:
<programlisting>
SELECT FROM CD WHERE title LIKE "%chopin%" OR notes LIKE "%chopin%";
</programlisting>
</para>
<para>
The % character is an SQL wild-card and takes care of finding the required
string somewhere inside the field; the `LIKE' operator is
case-insensitive by default. How could we achieve this with a
container-managed EJB? If `CD' is an EJB, the container-supplied method
`findAll()' in its home interface will get all the current instances of `CD'.
In practice it will do this by executing a statement like
<programlisting>
SELECT FROM CD;
</programlisting>
</para>
<para>
and then instantiating CD for each row found. At some point it will probably
store the primary key from each row of the database into the
appropriate attribute of each CD instance. Then the program must examine the
objects one at a time, checking whether they meet the required
criteria (i.e., the word `Chopin' in the appropriate attributes). As the
program iterates throuugh the objects, the server must cause their
attributes to be read from the table; it won't have done this until now
because it would try to conserve memory. So for each object examined
the server will generate SQL code like this:
<programlisting>
SELECT FROM CD WHERE ID=xxxx;
</programlisting>
</para>
<para>
Suppose there are 200 CDs known to the system. Rather than executing one SQL
statement to get a list of all matching CDs, the CMP scheme
has executed over 200 SQL statements to achieve the same effect. We can't
improve the situation by using a call to findByTitle then
findByNotes() because these methods only provide exact string matches. </para>
<para>
Another efficiency limitation comes from the way the database table is updated
when attributes change. There are two main ways to
achieve this. The server could execute an instruction like this:
<programlisting>
UPDATE CD SET artist="Bloggs" WHERE ID="200";
</programlisting>
</para>
<para>
for example. This is efficient, but requires the that `Artist' field really be
called `artist'. This makes it difficult to change the names of columns in
the table. Alternatively the server could do a SELECT to get the current
column values, delete the whole row, then insert a row with modified
values. This allows a number of values to change at once and, because all
values are written, it doesn't matter what the columns are called.
This is the approach that JBoss uses. The problem is that if a class has ten
persistent attributes, and they are altered one after the other, in the
worst case this results in ten row deletions and ten row insertions. </para>
</section>
<section>
<title>Limitations of late initialization </title>
<para>
Suppose we want to find whether a CD with a specific ID exists on the system.
With CMP this corresponds to finding whether there is a row in
the database table with the corresponding value of the `id' column. The code
in Java might look like this:
<programlisting>
// Get a reference to a CD Bean
Object ref = jndiContext.lookup("cd/CD");
// Get a reference from this to the Bean's Home interface
CDHome home = (CDHome)
PortableRemoteObject.narrow (ref, CDHome.class);
// Find the matching CD
CD cd = home.findByPrimaryKey("xxx");
</programlisting>
</para>
<para>
What will happen if `XXX' is not the ID of a CD that exists? There would seem
to be two sensible approaches. Either `findByPrimaryKey'
could throw an exception, or perhaps it could return a null reference. In
either case the client could easily tell whether the object exists. In
practice, the EJB server may do neither of these things. It may well return a
reference to a CD bean instance, which appears to be a perfectly
valid object. However, none of the object's attributes will be initialized;
initialization won't happen until the object is really required. This is done
to improve efficiency; there is, after all, no need to initialize the object
unless it will be needed. However, if the program continues to execute on
the basis that `cd' refers to a valid object, an exception will be thrown
later when the program tries to interact with it. This may not be a
problem; if the ID had been generated from some earlier database access then
we may be sure it really exists, and any failure to find it in the
database represents a serious failure. However, if the data has come from the
user, it is reasonable to expect some errors of typing or memory.
Things can be made more predictable by always reading one of the attributes of
an object after getting a reference to it, like this:
<programlisting>
CD cd = home.findByPrimaryKey("xxx");
String dummy = cd.getId();
</programlisting>
</para>
<para>
If there is no CD whose ID field is `XXX' then this will throw a
java.rmi.NoSuchObjectException. This gets around the problem
of late initialization, but at the cost of an additional SQL access.</para>
</section>
<section>
<title>Suitability of container-managed persistence </title>
<para>
In many applications of object-oriented programming we have had to accept that
some things that are philosophically objects are in reality
implemented as something else. The `something else' may be a row of a database
table, or a line of a text file, or whatever; at some point we
had to code the interface between the object-oriented system and the
`something elses'. Entity JavaBeans goes some way towards
eliminating this problem; things that are philosophically object can be
modelled as objects, with methods and persistence. But this comes at a
cost. It's worth asking whether the `CD' EJB in the tutorial example really is
an object in a meaningful sense. It has attributes, but it doesn't do
very much. We don't really gain all that much by making it an object; it could
have remained a database row, and been manipulated through the
`CDCollection' class. Of course this isn't as elegant, but elegance can come
at a high price. </para>
<para>In summary then, container-managed persistence is straightforward to
implement using JBoss (or any other EJB server, for that matter)
but needs to be used quite carefully if serious inefficiencies are to be
avoided.</para>
</section>
</section>
</section>
</chapter>
1.1 manual/src/docs/customizingjaws.xml
Index: customizingjaws.xml
===================================================================
<chapter><title>Customizing JAWS</title>
<para>Author:
<author><firstname>Sebastien</firstname><surname>Alborini</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section><title>Introduction</title>
<para>JAWS is the O/R mapper used by JBoss to manage CMP entity beans. JAWS
can be configured by putting a jaws.xml file in the
META-INF directory of your application. JAWS will read this file while
deploying your beans. Here is what you can do with jaws.xml:</para>
<itemizedlist>
<listitem><para>
Specify a datasource and the type-mappings to use with it
</para></listitem>
<listitem><para>
Set a bunch of options concerning jaws behavior
</para></listitem>
<listitem><para>
Specify how JAWS should build/use your tables
</para></listitem>
<listitem><para>
Define finders to access you entity beans
</para></listitem>
<listitem><para>
Define a type mapping
</para></listitem>
</itemizedlist>
<para>
If you want to know everything about jaws.xml, see the Jaws.xml DTD. The
general structure of the jaws.xml can be found here. All parts of
this file are optional: you only provide what you need!</para>
</section>
<section><title>Specifying a datasource</title>
<para>
A datasource is, mainly, a database plus a driver plus a connection pool. By
default, jboss uses the Hypersonic datasource. To add another
datasource, you have to declare it as a JMX MLet: see the manual.</para>
<para>
The second ARG of this MLet is the JNDI name of the datasource, i.e. the name
you have to use to access it. To tell JAWS to use this
datasource, simply add in your jaws.xml file a <![CDATA[ <datasource> ]]> tag
with the JNDI name in it.</para>
<para>
According to the type of the database, you probably also want to specify a
type mapping for this datasource. A type mapping tells JAWS
which jdbc types, which sql types to use for the storage of your cmp fields.
You just have to add a <![CDATA[ <type-mapping> ]]> tag with the name of the
type mapping in it. Type mappings for the most common databases are already
defined in jboss in a file called standardjaws.xml. Their
names are listed here:</para>
<itemizedlist>
<listitem><para>
Hypersonic SQL
</para></listitem>
<listitem><para>
InstantDB
</para></listitem>
<listitem><para>
Oracle
</para></listitem>
<listitem><para>
PointBase
</para></listitem>
<listitem><para>
PostgreSQL
</para></listitem>
<listitem><para>
SOLID
</para></listitem>
<listitem><para>
mySQL
</para></listitem>
<listitem><para>
DB2/400
</para></listitem>
<listitem><para>
MS SQLSERVER
</para></listitem>
</itemizedlist>
<para>
For instance, if you want to use the Postgres Database that you have deployed
in jboss.conf under the name MyPostgresPool, this is how
your jaws.xml file should look like:</para>
<programlisting>
<![CDATA[
<jaws>
<datasource>MyPostgresPool</datasource>
<type-mapping>PostgreSQL</type-mapping>
...
</jaws>
]]>
</programlisting>
<para>
If none of the predefined type mappings satisfies your needs, you can define
your own type-mapping.
</para>
</section>
<section><title>JAWS Options</title>
<para>
Here are the options you can set in JAWS:</para>
<itemizedlist>
<listitem><para>
create-table: this tells JAWS whether it has to try and create the
table for your beans at deployment time. It is turned on by
default. If the table already exists, JAWS will tell it to you, and
proceed.
</para></listitem>
<listitem><para>
remove-table: this tells JAWS whether it has to remove (drop) the table
of your bean at undeployment time. It is turned off by
default. You may want to turn it on to clean the database. Note that if
you change a cmp-field in a bean, you will probably have to
drop the table and create it again, since the schema will have changed.
</para></listitem>
<listitem><para>
tuned-updates: when this option is turned on (default) JAWS will only
update in the database the fields of your bean that have
actually changed.
</para></listitem>
<listitem><para>
read-only: tells whether JAWS will allow client application to modify
the state of your beans. Default is false. If true, JAWS will
perform no INSERT/UPDATE.
</para></listitem>
<listitem><para>
time-out: this option is only used when read-only is true. In this
case, JAWS will not refresh the state of your beans from the
database more than once every time-out milliseconds.
</para></listitem>
</itemizedlist>
<para>
Each of these options can be set either generally (it will affect JAWS for
your whole application) or on a per bean basis, or both of these.
JAWS will always read the defaults first, then override them with the
bean-specific configuration.
</para>
<para>
General settings: to set an option generally, you have to declare it in a
<![CDATA[ <default-entity> ]]> tag in jaws.xml. Here is the section as jaws
uses
it internally: you may want to override all or part of it:
</para>
<programlisting>
<![CDATA[
<jaws>
<default-entity>
<create-table>true</create-table>
<remove-table>false</remove-table>
<tuned-updates>true</tuned-updates>
<read-only>false</read-only>
<time-out>300</time-out>
</default-entity>
...
<jaws>
]]>
</programlisting>
<para>
Settings for a bean: to set an option for a particular bean, do it in the
corresponding <![CDATA[ <entity> ]]> section. For example, if you want JAWS to
drop the table for your CustomerBean only, your xml file will contain:
</para>
<programlisting>
<![CDATA[
<jaws>
...
<enterprise-beans>
<entity>
<ejb-name>CustomerBean</ejb-name>
<remove-table>true</remove-table>
</entity>
</enterprise-beans>
...
<jaws>
]]>
</programlisting>
<para>
Note that the <![CDATA[ <ejb-name>]]> tag must match the one declared in
ejb-jar.xml.
</para>
</section>
<section><title>Telling JAWS about your tables</title>
<para>
JAWS will use one different table for each of your CMP entity beans. The table
for one entity bean will contain one column for each of the
CMP fields of this entity.</para>
<para>
By default, JAWS will create the tables for you. The name of the table will be
the ejb-name of the bean, and the name of the columns will be
the name of the CMP fields. The jdbc type and the sql type will be the ones
given by the type-mapping. (see how the jdbc and sql type work
in the type mappings section)
</para>
<para>
However, you may want to override this behavior and tell JAWS which
names/types to use. For example, you may want JAWS to use an
already existing table. To do this, you must set these parameters in the
<![CDATA[ <enterprise-beans> ]]> section of you jaws.xml file.
</para>
<para>
Example 1: you create an entity bean that will represent a customer. You
already have the table in your database, it was created using the
following SQL statement:
</para>
<para>CREATE TABLE CUSTOMER (NAME VARCHAR(20),
ADDRESS VARCHAR(100), PHONE VARCHAR(20));</para>
<para>This is how the your xml file will look like:</para>
<programlisting>
<![CDATA[
<jaws>
<enterprise-beans>
<entity>
<ejb-name>CustomerBean</ejb-name>
<table-name>CUSTOMER</table-name>
<create-table>false</create-table>
<cmp-field>
<field-name>customerName</field-name>
<column-name>NAME</column-name>
</cmp-field>
<cmp-field>
<field-name>address</field-name>
<column-name>ADDRESS</column-name>
</cmp-field>
<cmp-field>
<field-name>phoneNumber</field-name>
<column-name>PHONE</column-name>
</cmp-field>
</entity>
</enterprise-beans>
...
</jaws>
]]>
</programlisting>
<para>
Example 2: your bank account bean has a String field to hold the VISA card
number. You don't want to use the default mapping for a String
(VARCHAR(256)) since a VISA Card number is not that long. Your xml file will
look like this:</para>
<programlisting>
<![CDATA[
<jaws>
<enterprise-beans>
<entity>
<ejb-name>Account</ejb-name>
<cmp-field>
<field-name>cardNumber</field-name>
<column-name>VISA</column-name>
<jdbc-type>VARCHAR</jdbc-type>
<sql-type>VARCHAR(16)</sql-type>
</cmp-field>
...
</entity>
</enterprise-beans>
...
</jaws>
]]>
</programlisting>
<para>Note that the contents of the <![CDATA[ <ejb-name>]]> tag and of all the
<![CDATA[ <field-name> ]]> tags must match the ones declared in
ejb-jar.xml.</para>
</section>
<section><title>Declaring finders</title>
<para>.
The finders to access your beans are all declared in the home interface. JAWS
automatically generates the following finders for you:
</para>
<itemizedlist>
<listitem><para>
findAll() will return a Collection of all the beans available
</para></listitem>
<listitem><para>
findByPrimaryKey(YourPK pk) will return a single bean with the
corresponding primary key (the primary key class is defined in
ejb-jar.xml)
</para></listitem>
<listitem><para>
for each of the cmp-fields of your bean, findByXX(YY fieldValue), where
XX is the name of the cmp-field (NOT case-sensitive)
and YY its class, will return a Collection of all the beans with the
right value in this field.
</para></listitem>
</itemizedlist>
<para>
Note that these finders are only generated if you declare them in your home
interface.
</para>
<para>
JAWS then allows you to define customized finders. These finders must also be
declared in the home interface of your bean. You must then
provide additional information in jaws.xml about the query to be used for this
finder. This is done in a <![CDATA[ <finder> ]]> section in the section for
your entity bean. You have to specify the name of the finder (the same as in
the home interface), the WHERE part of the query, and the
ORDER part.
</para>
<para>
Example: you want to select classes with a mininum number of students. Your
Class bean has the following structure:
</para>
<programlisting>
<![CDATA[
<ejb-jar>
<enterprise-beans>
<entity>
<ejb-name>ClassBean</ejb-name>
...
<prim-key-class>java.lang.String</prim-key-class>
...
<cmp-field>
<field-name>classId</field-name>
</cmp-field>
<cmp-field>
<field-name>teacherName</field-name>
</cmp-field>
<cmp-field>
<field-name>studentCount</field-name>
</cmp-field>
<primkey-field>classId</primkey-field>
...
</entity>
</enterprise-beans>
...
</ejb-jar>
]]>
</programlisting>
<para>
You want to define a method in ClassHome:
</para>
<programlisting>
public Collection findBigClasses(int minStudentCount, String teacher)
throws FinderException;
</programlisting>
<para>
Your jaws.xml file will contain the following:
</para>
<programlisting>
<![CDATA[
<jaws>
<enterprise-beans>
<entity>
<ejb-name>ClassBean</ejb-name>
<finder>
<name>findBigClasses</name>
<query>studentCount > {0} AND teacherName = {1}</query>
<order>studentCount DESC</order>
</finder>
</entity>
</enterprise-beans>
...
</jaws>
]]>
</programlisting>
<para>
Then a call to findBigClasses(100, "Jones") will generate
</para>
<programlisting>
SELECT classId FROM ClassBean
WHERE studentCount > 100 AND teacherName = Jones
ORDER BY studentCount DESC;
</programlisting>
</section>
<section><title>Defining a type mapping</title>
<para>
A type mapping tells JAWS how to map java objects to a specific database. For
example, some databases have a boolean type, and other
don't, so you have to map a java.lang.Boolean to a CHAR(5).</para>
<para>
Many type mappings are already defined in standardjaws.xml. If you want to
define a new one, I advise you to modify one of these: copy it
and paste it to the <![CDATA[<type-mappings>]]> section of your jaws.xml
file.</para>
<para>
A type mapping is constituted of several mappings, one for each java Class
that you need to map. If your class is not found in the mappings,
JAWS will use the mapping for java.lang.Object.</para>
<para>
A mapping comes in 3 parts:
</para>
<itemizedlist>
<listitem><para>
the <![CDATA[<java-type>]]> is the name of the java class you want to
map.
</para></listitem>
<listitem><para>
the <![CDATA[<jdbc-type>]]> is the jdbc type to use. Its value must be
one of the fields of java.sql.Types (e.g. BIT, CHAR...). This jdbc type will
be used by JAWS to determine which method to call on PreparedStatement
and ResultSet for INSERT / UPDATE / SELECT
queries.
</para></listitem>
<listitem><para>
the <![CDATA[<sql-type>]]> is the actual type in the database. This
value will only be used when JAWS creates your table.
</para></listitem>
</itemizedlist>
<para>
If the type mapping we provide for a particular database is faulty and you
find you have to modify it, please consider sharing your changes:
post the modified mapping on the JAWS mailing list.
</para>
</section>
</chapter>
1.1 manual/src/docs/designnotes.xml
Index: designnotes.xml
===================================================================
<chapter><title>Container architecture - design notes</title>
<para>Author:
<author><firstname>Vladimir</firstname><surname>Blagojevic</surname></author>
<email>[EMAIL PROTECTED]</email>
<author><firstname>Rickard</firstname><surname>Oberg</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section>
<title>Introduction</title>
<section>
<title>JBoss 1.0 (a.k.a EJBoss/NextGen)</title>
<para>JBoss 1.0, a.k.a EJBoss was started in March 1999 and reached 1.0
status in February 2000. The long march towards the promised land of
1.0'ness was not taken lightly. JBoss 1.0 established itself as a
technological leader with many ease of use features pioneered here
before finding their way to the broader audience of commercial
container developers. Mostly thanks to Rickard Oberg, the design
of 1.0 introduced many standard setting features such
as Proxy based deployment and distributed containers.</para>
<para>Marc Fleury had been working for almost 6 months on a
traditional,
compilation heavy approach to the container design, when Rickard came
along with the logical skeletons and the dynamic proxies as the basis
for a radically new design. Marc started coding feverishly and codenamed
the container "NextGen" truly believing it was a blueprint of things to
come, a "next generation" container.</para>
</section>
<section>
<title>JBoss 2.0</title>
<para>JBoss 2.0 that we are about to explore is truly a 3rd generation
container. It takes the patterns and ideas that were investigated in
1.0 and then does it right. Designed from the ground up to be modular,
JBoss introduces yet again many ground breaking features, such as
automated re-deploy, but most importantly a plug-in approach to
container implementation. Borrowing from the success that met with
Linux 2.0 and a it's modular approach to Open Source software
implementation, JBoss 2.0 is meant to be developed by distributed
parties each working on a cleanly separated part of the server.</para>
<para>JBoss 2.0 also standardizes on JMX, the Java Management eXtension
(TM) to offer standard interfaces to the management of its components
as well as the applications deployed on it. Ease of use is still the
number one priority here at JBoss, and JBoss 2.0 will set a new
standard.</para>
<para>We have to admit that it was hard to decide where to begin and
how
to proceed on this journey through JBoss. Although it's architecture is
clean, modular, and a mecca of best programming practices we know of,
the inhereted complexity of a distributed system carries it's weight.</para>
<para>In order to understand how JBoss 2.0 works one could go many
ways.
The approach we chose could be loosely described as "follow the call".
We'll not dwelve into container architecture directly, but in contrast
will build the foundation first on understanding client object structures,
how they pass the call to container over the network layer. Finally,
before we discuss container architecture in detail, we'll focus on
the container entry point.</para>
<para> With regard to container architecture, we'll explore all the
slices from the container entry point to database access structures,
focusing on various patterns, the renowned container plugin-in approach,
and how they relate to key points in EJB in general. </para>
<para>Now, let's not spoil all the fun parts.
Put your helmets on, we are going straight to the trenches!!!</para>
</section>
</section>
<section>
<title>Client Objects</title>
<section>
<title>EJBObject and EJBHome</title>
<para>As previously discussed in many EJB resources, an
<classname>EJBObject</classname> is an
object that represents a client's view of the Enterprise Java Bean. It is
generated by the container provider. A client never references an ejb bean
instance directly, but rather references the
<classname>EJBObject</classname> which implements the
bean remote interface. The <classname>EJBHome</classname> object is very
similar to <classname>EJBObject</classname> in
the sense that it is also generated by the container. Also, it implements
the bean's home interface, which is defined by the bean provider. Rather
than implementing business logic, however, it provides life-cycle
operations on the enteprise beans.</para>
</section>
<section>
<title>Virtual EJBObject - the big picture</title>
<para><classname>EJBObject</classname> is more of an abstract
idea than a
physical
implementation. So far, we know that
clients are given a remote
handle to EJBObjects, but how is the
EJBObject physically
implemented on the server side? Well,
it is not implemented at all !</para>
<para>Most EJB servers that are available today are literally
implementing
the EJB
specification. That is, for each
logical EJBObject there is one physical EJBObject that
receives requests.</para>
<para>This approach is very naive and may easily lead to
scalability
problems if there are many EJBObjects
alive at any one time.
In addition, this gives a rather
complex structure to the EJB container.</para>
<para>For example, one can have a finder method that returns
an enumeration
of
1.000.000 EJBObjects. Does this mean
that we now have to create 1.000.000
server EJBObject counterparts? This
would be a serious resource drain ! </para>
<para>In JBoss there is only one physical EJBObject that
serves all logical
EJBObjects. That physical EJBObject is
Container. For each EJB type there is
one container object, which plays the
role of EJBObject by wrapping all instances
of a particular EJB type.</para>
<para>JBoss' approach is superior in many aspects, and it
simplifies the
container architecture immensely.
Clients, however, never notice this. They have
something that looks and feels like a
real server EJBObject, but this is merely an
illusion. Behind the scenes there is
only one object (Container) handling all method
invocations. The final result is full
EJBObject conformity.</para>
</section>
<section>
<title>Two flavours of implementation</title>
<para>JBoss's client objects (<classname>EJBObject</classname>
and
<classname>EJBHome</classname>) are constructed as
dynamic proxies. But before we investigate dynamic proxies, it is
important to notice that there are two different implementations of
dynamic proxies, that are in fact almost totally the same. The package
jrmp13.interfaces* contains default implementation of
<classname>EJBObject</classname>
proxies that utilizes the core java.lang.reflect package of j2se 1.3.
In contrast, the package jrmp12.interfaces* contains
<classname>EJBObjects</classname> proxies
that are using JBoss's home brewed proxy framework of j2se 1.2.
This package is primarly intended to serve for "history proofing"
of JBoss (i.e., enabling JBoss to be used with j2se 1.2 version).</para>
<para>*Full package names are:</para>
<para>
<classname>org.jboss.ejb.plugins.jrmp13.interfaces</classname>
</para>
<para>
<classname>org.jboss.ejb.plugins.jrmp12.interfaces</classname>
</para>
</section>
<section>
<title>Relation to ContainerInvoker</title>
<para> The ContainerInvoker component, which we will focus on
in detail
later,
is responsible for maintaining <classname>EJBObject</classname> and
<classname>EJBHome</classname>. A closer look
at <classname>ContainerInvoker</classname> reveals an interface for
obtaining these objects.
Dynamic proxies of <classname>EJBObject</classname> and
<classname>EJBHome</classname> are created in
<classname>JRMPContainerInvoker</classname>,
a default implementation of the <classname>ContainerInvoker</classname>
interface.</para>
</section>
<section>
<title>Dynamic proxies</title>
<para>A dynamic proxy is an object that implements a list of
interfaces
specified at runtime when the object is created. A proxy interface
is an interface that is implemented by a proxy class. Each proxy
class instance has an associated invocation handler object, which
implements the interface InvocationHandler. </para>
</section>
<section>
<title>EJBObject as a dynamic proxy</title>
<para>EJBObject and EJHome object are created by following
classical
proxy instantiation technique:</para>
<para>
<programlisting>Proxy.newProxyInstance(bean.getRemoteClass().getClassLoader(),
new Class[] { bean.getRemoteClass() },
new EntityProxy());</programlisting>*</para>
<para>*Not exactly as is, simplified to a certain degree</para>
<section>
<title>What do we need to create a client proxy
?</title>
<para>In this particular case, given the classloader
that loaded
the entity bean's remote interface, its Class class, and the invocation
handler (<classname>EntityProxy</classname>), we are able to create a new
Proxy instance
which implements the bean's remote interface. Since
<classname>java.lang.reflect.Proxy</classname>
class is serializible, it can be sent to the remote client across
the network.</para>
</section>
<section>
<title>Relation between proxy and invocation
handler</title>
<para>The remote client, having a dynamic proxy class
that implements
the bean's remote interface, dispatches all method invocation on that
interface to the instance of the underlying invocation handler.</para>
</section>
<section>
<title>EJB proxy types</title>
<para>Depending on the type of the EJB bean on the
server, there are four
proxy classes: <classname>EntityProxy</classname>,
<classname>HomeProxy</classname>,<classname>StatelessSessionProxy</classname>
and <classname>StatefulSessionProxy</classname>.</para>
</section>
<para>All four proxies implement the
<classname>java.lang.reflect.InvocationHandler</classname>
interface and also subclass <classname>GenericProxy</classname>, which in
turn contains a
stub of the <classname>ContainerRemote</classname> interface implementor
from the server side.
That implementor is <classname>JRMPContainerInvoker</classname>.</para>
</section>
<section>
<title>Invoke method</title>
<para>Each of the proxy classes implements the only method
defined
in the <classname>InvocationHandler</classname> interface: invoke.
The invoke method intercepts all calls to the EJB remote
interface (client side) and depending on the particular type of EJB
method, does one of the following:</para>
</section>
<para>- handles the method locally in the <classname>Proxy</classname>
class
- passes the method call accross the wire to the remote EJB container
- invokes the method in the local EJB container</para>
<section>
<title>Advantages</title>
<para>This design of client objects gives maximum flexibility
in the
following sense: all calls that can be handled by clients themselves
are handled locally, preventing the roundtrip across the wire and
saving the container from unneccessary loading. Calls coming from other
EJBs, but local to the JVM, are also optimized since they bypass the network
transport layer and call the specific underlying container directly.
Finally, only calls that absolutely must leave the local VM are passed
across the wire.</para>
</section>
<section>
<title>Closing the first half of the circle</title>
<para>Let's trace the remote call on busines method B of an
entity
bean.</para>
<para>First, the method call goes on the proxy interface where
it is
dispatched to its invocation handler, which in this case is EntityProxy.
Entity proxy converts the call into a
<classname>RemoteMethodInvocation</classname>object and stuffs it
into a <classname>MarshalledObject</classname>. Using a stub of the
<classname>JRMPContainerInvoker</classname>, the remote
call is sent over the "wire" to the server's
<classname>JRMPContainerInvoker</classname> object
where it is unpacked from <classname>MarshalledObject</classname> and handed
off to the container.</para>
<para>*Note that, since the jdk1.2 release, skeletons are
avoided on the
server side. Consult RMI specification for more info.</para>
</section>
</section>
<section>
<title>JMX - foundation of JBoss infrastructure</title>
<section>
<title>Introduction</title>
<para>JMX technology represents a standard coherent
framework for
instrumentation and management of Java
technology-based resources. JMX defines a management architecture, APIs, and
management services all
under a single umbrella specification. On top of this specification promises
hooks into existing management
systems.</para>
</section>
<section>
<title>JMX core components</title>
<para>MBeanServer is core JMX abstraction, a component
which provides
services for manipulating MBeans. All
management operations performed on MBeans are done through MBeanServer
interface. MBeanServer
contains the necessary methods for the creation, registration, and deletion of
MBeans as well as the access
methods for registered MBeans. This is the core component of the JMX
infrastructure.</para>
<para>MBean is a "regular" Java component volunteering
to be instrumented.
Every MBean component which is
added to the MBeanServer becomes manageable: its attributes and operations
become remotely accessible
through the connectors/adaptors connected to that MBeanServer. A Java object
cannot be registered in
the MBeanServer unless it is a JMX compliant MBean.</para>
</section>
<section>
<title>JBoss and JMX</title>
<para>MBeanServer in Jboss architecture plays a role
of microkernel
aggregator component. All other managable
MBeans components are plugged into MBeanServer. The kernel in that sense is
only an aggregator, and not
a source of actual functionality. The functionality is provided by MBeans and
infact all major JBoss
components, are managable MBeans interconnected through MBeanServer. The
managibility is provied by
MBeanServer which instuments registered MBeans.</para>
<para>The modular architecture of JBoss , provided by
JMX foundation
moves all dependency checking from
compile time to run-time enviroment. The rigourous runtime depedencies
check mechanism, in the form
of JBoss' DependencyManager component, enforces dependencies between different
resources and services.</para>
<para>It is important to notice that "management
dependencies" are
something independent of the managed
blocks but dependent on the context of a particular deployment/environment. In
any case, the dependencies
are runtime oriented and the external management of them (JMX) is the way
to go.</para>
</section>
</section>
<section>
<title>ContainerInvoker - Container entry point</title>
<section>
<title>Introduction</title>
<para>Certainly one of the most important parts of a
distributed system
is its RPC interface, as well as techniques used in passing that RPC
call between different parts of the system.</para>
<para>The component that plays the role of the container entry
point, a
"call
router", to insides of the container is the
<classname>ContainerInvoker</classname>. By closely
looking at this entry point to the JBoss container, one would understand
the semantics of calls made from clients, client object structure, the
passing
of client calls over the network layer (a.k.a "wire") and unpacking
them in a local VM. Similar semantics are employed in returning the result
of the call and how it is handled on the client side. Also, great attention
has to be dedicated to methods employed in bypassing the network layer if
these
calls are made from clients local to the container, i.e intra-VM.</para>
</section>
<section>
<title>ContainerInvoker in focus</title>
<section>
<title>How are calls passed into a container?</title>
<para>Container invoker utilizes RMI exporting* to
make itself
available to remote clients. By implementing
<classname>ContainerRemote</classname> interface,
which in turn extends the familiar <classname>java.rmi.Remote</classname>
interface,
ContainerInvoker acts as an RMI server object and as such is able to
accept calls that come from both remote clients (other JVMs) and
from other beans "living" in containers of the same EJB
application (within the same JVM).</para>
</section>
<section>
<title>ContainerRemote interface - two flavours of
invoke methods</title>
<para>Before going further into the details, let's
look closer into
<classname>ContainerRemote</classname> interface. It has two methods,
<function>invoke</function> and <function>invokeHome</function>, each of
which
has two flavors:</para>
<para>
<programlisting>public MarshalledObject
invoke(MarshalledObject mi)
throws Exception;</programlisting>
</para>
<para>
<programlisting>public Object invoke(Object
id, Method m, Object[] args,
Transaction tx,
Principal identity,
Object credential )
throws Exception;</programlisting>
</para>
<para>The first accepts only one parameter
(<classname>MarshalledObject</classname>), while
second accepts "regular" java objects. Why is this distinction
between the two sets important? </para>
<para>The distinction exists exactly for the reason
that it enables the
container to accept both remote and local client calls. But it is
important
to notice that not only does this design approach enable two different
call methodologies, it optimizes them at the same time.</para>
</section>
<section>
<title>Remote call unpacking stage</title>
<para>Remote calls are unpacked from
<classname>MarshalledObject</classname>.
<classname>MarshalledObject</classname>
contains a byte stream with serialized representation
of an object given to its constructor. In our case, this object is
<classname>RemoteMethodInvocation</classname>.
The <classname>RemoteMethodInvocation</classname> instance,
created by a remote client proxy, describes all needed attributes
of an EJB method call. Some of these attributes, as you
may have guessed by now, are the ID of the object, a method to
invoke, security credentials, principal of the caller(identity),
and a transactional context of the call.</para>
</section>
<section>
<title>MethodInvocation</title>
<para>Upon receving
<classname>MarshalledOjbect</classname> from client
proxy, <classname>ContainerInvoker</classname>
recreates a copy of the original
<classname>RemoteMethodInvocation</classname>
object, by deserializing it from the contained byte stream in
<classname>MarshalledObject</classname>.
<classname>RemoteMethoInvocation</classname> is then converted to
<classname>MethodInvocation</classname> and handed off to the
container.</para>
</section>
<section>
<title>Bean to Bean calls</title>
<para>Local calls coming from clients in the same VM,
usually a
"bean/bean" method call, are directly handed off to the container.
This bypasses the network layer, and serialization/deserialization
stage of the call that remote method calls have to go through.</para>
</section>
<section>
<title>Other ContainerInvoker duties</title>
<para>Before forwarding a call to the container,
<classname>ContainerInvoker</classname> also
resets the call's thread classloader with the specified container
classloader, propagates transaction, and security context. </para>
<para>Another important role played by
<classname>ContainerInvoker</classname> is that it
provides implementation of <classname>EJBObject</classname> and
<classname>EJBHome</classname> parts of container.
As mentioned before, <classname>ContainerInvoker</classname> creates
<classname>EJBObject</classname> and <classname>EJBHome</classname>
in the form of dynamic proxies.</para>
<para>For example, an
<classname>EntityBean</classname> finder may result
in a set of primary
keys whose EJB-objects should be returned to the client. The
<classname>ContainerInvoker</classname> is then responsible for creating
<classname>EJBObject</classname>
instances that can be used by the client, as specified in the
EJB 1.1 specification. The client must then be able to remotely
access the container and actual bean instances through
these <classname>EJBObjects</classname>.</para>
</section>
<section>
<title>Why ContainerInvoker if we have
container?</title>
<para>One may wonder why there is such a big
distinction between
container invoker and the container.
<classname>ContainerInvoker</classname> also
uses the naming tree. Why should the container invoker know
anything about the naming tree? You end up having the container
invoker taking care of all the important registrations...</para>
<para>Wasn't the container responsible for all this
crucial work?</para>
<para>No, this architectural approach was intentional
in JBoss. Since
different distribution protocols use different naming systems
(IIOP would use the CORBA naming system), the only part of the
container that knows what naming system to use is the container invoker.
Now, if we want to add another/different distribution protocol to JBoss, we
can
simply implement it in the container invoker; everything else stays
untouched.
ContainerInvoker is free to choose which distribution protocol to use
to access the container. Valid options would be JRMP, IIOP, or SOAP. The
default
plugin uses the standard RMI protocol JRMP to allow client access to
the container. </para>
<para>*Exporting - making object available to accept
incoming calls by
listening on specified TCP port</para>
</section>
</section>
</section>
<section>
<title>Container</title>
<section>
<title>Concepts</title>
<para>A <classname>Container</classname> is the component that
runs a
particular EJB. When an
EJB-jar is deployed, typically a number of containers are created
which are connected internally into Applications. The
Application lets Containers handle references between beans, for
example for JNDI EJB-references as specified in the EJB 1.1
specification.</para>
<para>But let's not dive into the nuts and bolts of the
container
component without first looking into the container's creation process.
The component responsible for creating the container is the container
factory.</para>
</section>
<section>
<title>Container Factory</title>
<para>The container factory, as its name implies, simply
creates containers.
Simple, right? Wrong !!! Lets investigate this process in more
detail.</para>
<section>
<title>Introduction</title>
<para>Given an EJB-jar that is ready for deployment,
the container factory
will create and initialize the necessary EJB-containers - one for each
deployed EJB. The factory contains two central methods:
<function>deploy</function> and
<function>undeploy</function>. The <function>deploy</function> method takes
a URL, which either points to an
EJB-jar, or to a directory whose structure is the same as a valid
EJB-jar(convenient for development purposes). Once a deployment has
been made, it can be undeployed by calling <function>undeploy</function> on
the same URL.
A call to <function>deploy</function> with an already deployed URL will
cause an <function>undeploy</function>
followed by deployment of the URL, i.e. a re-deploy. JBoss has support
for full re-deployment of both implementation and interface classes,
and will reload any changed classes. This will allow you to develop
and update EJBs without ever stopping a running server.</para>
</section>
<section>
<title>What the container factory needs to know</title>
<para>In order to properly deploy the bean into a
container, the container
factory
has to have "intimate" knowledge about the bean being deployed to the
finest level of granularity. This is where the notion of bean metadata
comes into the picture. The metadata package, which in turn utilizes a
standard DOM document model, creates an "object-tree" in-memory replica of
ejb-jar.xml file. Having an object tree structure of bean metadata,
the container factory can easily access it and then succesfully deploy
a bean into a container. Bean metadata is actually a super set of
other finer-grained metadata components like method, ejb-ref, environment
entries, resource entries metadata.</para>
</section>
<section>
<title>Container configuration</title>
<para>Besides standard EJB 1.1 ejb-jar.xml file that
contains metadata
about beans being deployed, JBoss defines its own container
configuration file - standardjboss.xml. Standardjboss.xml specifies
default container configurations for each EJB bean type. Each configuration
specifies which components to use, such as container invoker type, instance
caches/pools and their sizes, persistence manager etc.</para>
</section>
<section>
<title>Configuration flexibility</title>
<para>A quick look at standardjboss.xml gives us a
hint about all default
container configurations. EJB adminstrator/developer is also given an
opportunity to override these default container settings in jboss.xml
file. The advantage of this approach is that it gives great flexibility
in the configuration of containers. As we have seen, all container
configuration attributes have been externalized and as such are easily
modifiable. Knowledgeable developers can even implement specialized
container components such as instance pools or caches and easily integrate
them with the container.</para>
</section>
<section>
<title>Bean Verifier</title>
<para>As an option, Jboss also attempts to verify EJB
1.1 specification
compliance of
the beans. For more details, the curious reader should look into the
verifier
package.</para>
</section>
<section>
<title>Deployment semantics</title>
<para>Having a bean and container metadata, the
container factory iterates
over
all beans it has to deploy and:</para>
<para>- creates specific container subclass
- sets all container attributes from container metadata*
- adds all container interceptors*
- adds container to application
- after all beans have been succesfully deployed, starts application</para>
<para>*Note the difference between container
interceptors in specific
container
subclasses</para>
<para>*The metadata specifies the type of TM
(transaction manager)
to use but, in fact, we need look it up from the naming tree. In fact,
there is (and should be) only
one TM per VM since transactions have to be coordinated across containers.
Also note that <classname>EJBSecurityManager</classname> and
<classname>RealmMapping</classname> are shared between
containers (for more details refer to the security section of this
paper).</para>
</section>
</section>
<section>
<title>Automatic deployment</title>
<section>
<title>Introduction</title>
<para>The container factory can be invoked manually
from a management
console or automatically by using the <classname>AutoDeployer</classname>.
AutoDeployer
(which is an MBean) is a component that periodically checks EJB-jars
for modification timestamps. If an update has been made the EJB-jar
is re-deployed. When the server is started and an EJB-jar is found
it will be deployed automatically.</para>
</section>
<para>The deployer is given a URL to watch. The URL can point
to one of
three things:</para>
<para>- EJB-jar</para>
<para>- directory whose contents are structured like an
EJB-jar. Timestamp
checks will be done on the META-INF/ejb-jar.xml file.</para>
<para>- directory into which EJB-jar files or directories
containing
valid EJB-jar contents is placed. This may only be a file URL,
since it is not possible to do file listing checks on HTTP
URL's.</para>
<section>
<title>Advantage of automatic deployment</title>
<para>The last variant is very powerful. The default
configuration of
JBoss starts an <classname>AutoDeployer</classname> that checks the /deploy
directory. Here
you can place any EJB-jars that you want to be deployed on startup.
If you want to add deployments at runtime you simply drop them in
that directory.</para>
</section>
</section>
<section>
<title>EnterpriseContext</title>
<para>
<classname>EnterpriseContext</classname> and its
subclasses,
<classname>StatefulSessionEnterpriseContext</classname>,
<classname>StatelessSessionEntepriseContext</classname>,
and <classname>EntityEntepriseContext</classname> implement
<classname>EJBContext</classname> part of EJB 1.1 spec.</para>
<section>
<title>Client view</title>
<para>From a bean's perspective
<classname>EJBContext</classname> is a
gateway to container;
it represents a way for a bean to perform callbacks to the
container.</para>
</section>
<section>
<title>Container view</title>
<para>From a container's perspective, the container
uses
<classname>EntepriseContext</classname> to
associate a bean instance with all information that the container
needs about
that instance to properly manage it. This infomation includes
a callback reference to the container hosting the instance,
synchronization associated with
that instance, instance's transaction,
<classname>Principal</classname> and object Id.
Simply put, <classname>EntepriseContext</classname> associates a
bean's instance with its metadata.
It is the container's responsibilty to manage bean's context, which
changes over the lifecycle of a bean.</para>
</section>
</section>
<section>
<title>Container's nuts and bolts</title>
<section>
<title>Container class itself</title>
<para>JBoss container is mainly a framework into which
one can plug in
implementations of various parts. The
<classname>Container</classname> itself does not perform
any significant work other than connecting the various plugins.
There are three subclasses of <classname>Container</classname>, each
one implementing a
particular bean-type:</para>
<para>
<classname>EntityContainer</classname> handles
EntityBeans,
<classname>StatelessSessionContainer</classname> handles Stateless
SessionBeans, and
<classname>StatefulSessionContainer</classname> handles Stateful
SessionBeans.</para>
<para>They are very similar, but are different in some
respects. The
stateless session container does not have an instance cache (since
no instances have identity), and the entity container has an
<classname>EntityPersistenceManager</classname> to help it with
persisting entity beans in
various storages.</para>
</section>
<section>
<title>Container plugin framework</title>
<para>The plugins can be added by implementing various
interfaces, and
by selecting them in the JBoss-specific deployment XML file (which
can be edited in a GUI-tool). The interfaces are:</para>
<para>
<classname>InstanceCache</classname>,
<classname>InstancePool</classname>,
<classname>Interceptor</classname>,
<classname>EntityPersistenceManager</classname>,
<classname>StatefulSessionPersistenceManager</classname>
</para>
<para>
<classname>InstancePool</classname> and
<classname>Interceptors</classname> are used in all three different types of
containers. <classname>InstanceCache</classname> is only used for
entity beans and stateful
session beans. <classname>EntityPersistenceManager</classname> is
only used for entity beans.
<classname>StatefulSessionPersistenceManager</classname> is only used
for stateful session
beans.</para>
<para>These interfaces are described in detail below.
All plugins have
a callback to the container through which they can access all other
plugins or configuration information. The container's main
responsibility
is therefore to manage the plugins, and to see to it that the plugins
have all
the information they need in order to implement some
functionality.</para>
<section>
<title>Interceptor</title>
<section>
<title>Creation and ordering</title>
<para>All interceptors are created and
added to the interceptor
linked-list by
the container factory. The last interceptor is not added by the
container
factory but rather by the container itself.</para>
</section>
<para>The order of the interceptor in the
chain is not accidental. The
idea
behind ordering is that intereceptors that are not tied to a particular
EnterpriseContext instance are positioned before interceptors that
interact with caches and pools.</para>
</section>
<section>
<title>Structure, complexity,
cardinality</title>
<para>Implementors of the
<classname>Interceptor</classname> interface
form
a linked-list like
structure through which the <classname>MethodInvocation</classname>
object
is passed. The first
interceptor in the chain is invoked when
<classname>ContainerInvoker</classname> hands off
<classname>MethodInvocation</classname> to the container. The last
interceptor invokes the business
method on the bean. There are usually between 3 and 6 interceptors in
a chain depending on the bean type and container configuration.
Interceptor
semantic complexity ranges from simple to complex ones, but under the
cover they all present the same simple interface. An example of a
simple interceptor would be <classname>LoggingInterceptor</classname>,
while a complex example is
<classname>EntitySynchronizationInterceptor</classname>.</para>
</section>
<section>
<title>Advantages</title>
<para>One of the main advantages of
<classname>Interceptor</classname>
pattern is flexibility
in the arrangement of interceptors, as well as a clear semantic
distinction
between different interceptors. For example, logic for transaction and
security is in <classname>TXInterceptor</classname> and
<classname>SecurityInterceptor</classname> correspondingly.</para>
<para>If any of the interceptors fail, we
don't have to continue the call
further
through, which is very useful if the interceptor that failed is before
complex
structures like caches.</para>
</section>
</section>
<section>
<title>Instance Pool</title>
<section>
<title>Recycling pool for bean
instances</title>
<para>
<classname>InstancePool</classname> is
used to manage the EJB-bean
instances that are
not associated with any identity. In fact, to be exact,
<classname>EnterpriseContext</classname> objects that wrap
non-associated bean instances
are pooled in this data structure.</para>
</section>
<section>
<title>Pool types and cardinality</title>
<para>Depending on the underlying bean type
hosted in a container, there
are three different instance pool types. However, it is important
to notice that each container has only one pool of either type.</para>
</section>
<section>
<title>Size and roles</title>
<para>Depending on the configuration, a
container may choose to have a
certain
size of the pool containing recycled instances, or it may choose to
instantiate and initialize an instance on demand.</para>
<para>The pool is used by the
<classname>InstanceCache</classname> to
acquire free instances
for activation, and it is used by Interceptors to acquire instances
to be
used for Home interface methods (create and finder calls).</para>
</section>
</section>
<section>
<title>Instance Cache</title>
<section>
<title>Container's cache structure</title>
<para>
<classname>InstanceCache</classname>
handles all EJB-instances that are
in a active
state, i.e. bean instances that have an identity attached to
them.</para>
</section>
<section>
<title>Entity and stateful session bean
cache</title>
<para>Only entity and stateful session beans
are cached. The cache key
of an entity bean is the primary key. It is the session id for
stateful
session beans.</para>
</section>
<section>
<title>Roles</title>
<para>
<classname>InstanceCache</classname>
handles the list of active
instances, and is also
responsible for activating and passivating these instances. If
an instance with a given identity is requested, and it is not
currently active, the <classname>InstanceCache</classname> must use
the <classname>InstancePool</classname>
to acquire a free instance, and the persistence manager to
activate the instance. Similarly, if it decides to passivate
a certain active instance, it must call the persistence manager
to passivate it and release the instance to the
<classname>InstancePool</classname>.</para>
</section>
</section>
<section>
<title>EntityPersistenceManager</title>
<para>The
<classname>EntityPersistenceManager</classname> is responsible
for the persistence
of EntityBeans. This includes:</para>
<para>- Creating EntityBeans in a storage
- Loading the state of a given primary key into an EJB-instance
- Storing the state of a given EJB-instance
- Removing the state from storage
- Activating an EJB-instance
- Passivating an EJB-instance</para>
<para>As per EJB 1.1 specification, JBoss supports two
entity bean
persistance semantics: CMP (Container Managed Persistence) and
BMP (Bean Managed Persistence).</para>
<para>The CMP plugin,
<classname>CMPPersistanceManager</classname> uses
the default implementor of
<classname>EntityPersistanceManager</classname>,
<classname>JAWSPersistanceManager</classname> (JAWS-Just Another Web Store).
JAWS performs performs basic O/R functionality against a
JDBC-store.</para>
<para>The BMP implementor of the
<classname>EntityPersistenceManager</classname>
interface is
<classname>BMPPersistanceManager</classname>. BMP persistance manager
is fairly simple
since all persistence logic is in the entity bean itself. The only
duty of the
persistence manager is to perform container callbacks.</para>
</section>
<section>
<title>StatefulSessionPersistenceManager</title>
<para>The
<classname>StatefulSessionPersistenceManager</classname> is
responsible for
the persistence of Stateful SessionBeans. This includes:</para>
<para>- Creating stateful sessions in a storage
- Activating stateful sessions from a storage
- Passivating stateful sessions to a storage
- Removing stateful sessions from a storage</para>
<para>The default implementation of the
<classname>StatefulSessionPersistenceManager</classname>
is <classname>StatefulSessionFilePersistenceManager</classname>. As
its name implies,
<classname>StatefulSessionFilePersistenceManager</classname> utilizes
the underlying file system
to persist stateful SessionBeans. More specifically, persistence
manager
serializes beans in flat file under bean name + bean Id .ser files.
Having a .ser file per bean instance, the Persistance Manager is able
to
restore a
bean's state for activation and respectively store its state during
passivation.</para>
</section>
</section>
</section>
<section>
<title> Transaction support </title>
<section><title>Background</title>
<para>In the world of distributed transaction processing (DTP) a
series of
specifications developed by OpenGroup
(www.opengroup.org) represent the most widely adopted DTP model. </para>
<para>Opengroup specifications define major components participating
in the
DTP
model as well as a set of APIs
that define communication between these components. Components
participating in the DTP model are:
application programs, resource managers, and a transaction manager. The
interface
defined between application
programs wishing to participate in global trasactions and the transaction
manager is called the TX
interface, while the interface between transaction managers and the resource
managers is called the XA interface.</para>
<para>Sun Microsystems Inc followed this DTP model and as part of J2EE
introduced the Java Transaction Service (JTS)
and the Java Transaction API (JTA) specifications.</para></section>
<section><title>JTS and JTA</title>
<para>The difference between JTS and JTA is often a source of
confusion.
Simply
put JTS defines above mentioned components
participating in the DTP model, while JTA captures interfaces between
them.</para>
<para>JTS defines five major players in the DTP model of Java
Enterprise
middleware:</para>
<para>Transaction Manager as a core component which provides services
of
transaction resource management ( i.e resource
enlistment, delistment), transaction demarcation, synchronization notification
callbacks, trasaction context
propagation and two-phase commit initiation and recovery coordination with
resource managers.</para>
<para>The application server provides infrastructure required to
support the
application run-time environment.</para>
<para>A resource manager is a component that manages access to a
persistent
stable storage system. Each resource manager cooperates with a
Transaction Manager in two-phase commit intiation and failure recovery. An
example of resource manager would be
database driver.</para>
<para>EJB's can either use declarative transaction management
specified in
the ejb-jar.jar xml descriptor, or programmatic transaction manager
using the <classname>UserTransaction</classname> interface. Either way, the
transaction services are provided by the application server.</para>
<para>A communication resource manager supports transactional context
propagation. Simply put this component allows
the transaction manager to participate in transactions initiated by other
transaction managers. JTS does not
specify a protocol for this component.</para></section>
<section><title>Core implementation</title>
<para>Jboss includes it's support of JTS and JTA specifications in the
jboss.tm package. This package include implementation of
TransactionManager , Transaction, Xid and Synchronization from JTA
specification. </para>
<para>However, the key class is TxCapsule. TxCapsule is has a very
abstract notion but it closely matches the idea of
transaction context. Transaction context in turn is best thought of as a
state of all transactional operations on the
participating resources that make up one global transaction . Therefore
transactional context, or in Jboss's case
TxCapsule, captures all participating XaResources and their states, all
particiating threads as well as a global Xid
identifying global transaction.</para>
<para>TxCapsule provides the real meat. It enables enlisting and
delisting
of transactional resources, importing of
transactions into capsule, provides creational point and access to Xid of the
current global transaction, calls
Synchronization callback but most importantly it initiates the two-phase commit
protocol as well as rollback mechanisms
defined by the two-phase commit protocol.</para>
<para>TransactionImpl implements Transaction interface from JTA. Each
transaction is a part of TxCapsule which in turn can
"host" transactions representing the TxCapsule. All of TransactionImpl methods
are basically indirection calls to the hosting
TxCapsule. </para>
<para>TxManager implements TransactionManager interface defined in
JTA. As
you might have guessed by now, it controls the lifecycle of all
TxCapsules. Since TxCapsule is a relatively heavyweight object, capsules
are recycled in a soft reference queue.</para></section>
<section><title>TxInterceptor</title>
<para>Following the previously introduced interceptor framework JBoss
introduces two transactional interceptors TXIntereceptorBMT
and TXIntereceptorCMT. Both interceptors closely interact with TxManager in
order to achieve proper transactional semantics.</para>
<para>TXIntereceptorBMT provides an instance of UserTransaction to the
right
transactional context. TxInterceptorBMT is used
in the case of user demarcated, i.e explicit transactional management. For
more information on details of semantics
refer to p174 of EJB1.1 spec.</para>
<para>TxInterceptorCMT moves all transactional management work to the
container. Depending on the transaction attributes specified in th
ejb-jar.xml file
(i.e TX_REQUIRED, TX_SUPPORTS, TX_REQUIRES_NEW etc) the container decides how
to manage
the transactional context of the invoked call.</para></section>
</section>
<section>
<title>Security</title>
<section>
<title>Authentication - checking credentials</title>
<para>
<classname>Credential</classname> is an object that
the client supplies to
authenticate himself to the
system. <classname>Credential</classname> might be a password, a digital
signature, or another identifier.
It might also be a wrapper of that credential to indicate that the jboss
server trusts the invoker about the principal and no authentication is
necessary (e.g. for in-VM invocations, or invocations from a web
container).</para>
<para>The authentication interface is:</para>
<para>
<programlisting>public interface
org.jboss.system.SecurityManager
{
public boolean isValid( Principal principal,
Object credential );
}</programlisting>
</para>
<para>Judgments about validity are based on the
<classname>Principal</classname> class type,
<classname>Principal</classname> name, and credential. Typically, one
implementation
exists per security realm.</para>
<para>The security manager implementation is registered in the
JNDI
namespace as "SecurityManager." and is shared between containers.
This system level implementation would only delegate to the realm-level
implementations to see if the Principal/credential pair were
valid.</para>
</section>
<section>
<title>Authorization - checking access to resources</title>
<para>Authorization interface is defined as follows:</para>
<para>
<programlisting>public interface RealmMapping
{
public boolean doesUserHaveRole( Principal principal,
Set roleNames );
}</programlisting>
</para>
<para>A <classname>RealmMapping</classname> describes a
relation between a
list of principals,
and a set of roles assigned to each principal. Unlike
SecurityManagers, RealmMappings are specific to a particular
J2EE application. So the relationship is the following:
J2EE app has many realms, a realm has many principals,
and a principal has many roles.</para>
<para>The <classname>RealmMapping</classname> interface is
used in
conjunction with the
authorization information in the EJB 1.1 or 2.0 deployment
descriptor. It is also used for the implementation of
<function>isCallerInRole</function> call. Set of roleNames would have
only one role in
that case.</para>
<para>A <classname>CacheRealmMapping</classname> is a
"meta-level"
implementation of
RealmMapping that handles lists of realms for a particular J2EE
application. It is called <classname>CacheRealmMapping</classname>
because we cache
information about a particular principal if access to the
persistent mapping is expensive.</para>
</section>
<section>
<title>SecurityInterceptor</title>
<para>The <classname>SecurityInterceptor's</classname> first
task would be
to use the
SecurityManager to authenticate the <classname>Principal</classname>,
based on the
credential available in <classname>MethodInvocation</classname>.</para>
<para>Then, <classname>SecurityInterceptor</classname>, given
a method that
has to be invoked,
retrieves methodPermissions (set of roles) from the container and checks
if caller's principal has any of those retreived roles.</para>
</section>
</section>
<section>
<title>Tracing the call through container</title>
<para>The preceding sections discussed specific pieces of call handling
at length. Now it is time to put all the pieces together to see how a
complete method invocation is handled. In particular, let's look at the
handling of method calls on an Entity Bean.</para>
<para>The call is first logged. Then the TxInterceptor decides how to
manage
transactions for this call. The information needed for this decision
comes from the standard XML descriptor. Then, the SecurityInterceptor
checks if the caller is allowed to perform this call, again by using
information from the XML descriptor. Up until this point no instance
has been acquired. After all interceptors have been passed the container
will invoke the business method on the EJB instance, so now we
acquire this instance.</para>
<para>The interceptor calls the InstanceCache with
the given primary key to perform this. Since the cache does not yet
have an instance associated with the given primary key, it first gets
a free instance from the instance pool, which it associates with the
primary key. It then calls the persistence manager which will activate
the instance. This usually only involves calling ejbActivate.</para>
<para>After instance acquisition the next interceptor deals with how this
instance is
synchronized with the database. There are a number of options (load on
transaction start, load on each call, load on activate, etc.) and the
interceptor has been configured to perform one of these options. In
this example it will load on activate, so it calls the persistence
manager to perform this. This will cause an ejbLoad call to be made
on the instance.</para>
<para>Next, the last interceptor is invoked, which is the
container itself. The container always adds itself as the last interceptor
at the end of the chain. The call is now delegated to the EJB instance.
The instance performs some work, and returns a result. The interceptor
chain is now followed in reverse by having each interceptor return from
the invoke-operation. The instance synchronization interceptor chooses
to store the current state into the database and hence calls storeEntity
on the persistence manager. Another valid option would be to wait until
transaction commit.</para>
<para>Next, the instance is returned to the cache. If the
transaction does not end with this call, it will first lock the instance
to this transaction so that no other transaction may use it for the
duration of this current transaction. This is the same as pessimistic
locking. The transaction interceptor handles the method return according
to the transaction settings, possibly commiting or rollbacking the current
transaction. Finally, the container invoker returns the result to the
client. This completes the call.</para>
<para>As you can see, all implementation decisions are performed by
various
plugins.
These decisions are fairly loosely coupled, which allows the deployer of
the EJB-application to tweak the behaviour of the container to a great
degree. This also allows for a number of independent plugins to co-exist,
each one allowing for slightly, or radically, different behaviour.</para>
<para>For example, some persistence managers could use an XML-file as
the
backing
store instead of an RDBMS, and some security interceptor could use ACL's
from a database instead of the XML descriptor to perform security checks.
Or multiple security checks could be done by configuring the container
to have several security interceptors of different types. All of these
options are available by this componentized container architecture.</para>
</section>
</chapter>
1.1 manual/src/docs/howtoejx.xml
Index: howtoejx.xml
===================================================================
<section><title>EJX/AWT Development HowTo</title>
<para>Author:
<author><firstname>Andreas</firstname><surname>Shaefer</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section><title>Introduction</title>
<para>
This How To serie is about how to develop EJX plugins with the help of
Rickard's AWT, XML and
BeanContext and NOT about how to use EJX and its plugins (at least for
now)!! </para>
<orderedlist>
<listitem><para><link linkend="ejx1">Insights to EJX internals by
Simon Bordet</link></para></listitem>
<listitem><para><link linkend="ejx2">Getting started with
EJX</link></para></listitem>
<listitem><para><link linkend="ejx3">GUI
Basics</link></para></listitem>
</orderedlist>
<para>
Next steps
</para>
<orderedlist>
<listitem><para>How to use resources (especially XML files) in
EJX </para></listitem>
<listitem><para>Advanced GUIs </para></listitem>
</orderedlist>
</section>
<section id="ejx1"><title>EJX Insights</title>
<para>EJX (created by Rickard �berg and are available at his DreamBean Website:
www.dreambean.com) is a launcher for JavaBean plugins
that are written following the Glasgow specification, in particular the Extensible
Runtime Containment and Services Protocol. This
document is intended for programmers that want to write plugins for EJX, and will
(try to) explain the insights of the bean context
hierarchy of EJX, and also classloader issues regarding this hierarchy. </para>
</section>
<section><title>The launcher</title>
<para>
com.dreambean.ejx.editor.Main is the launcher for EJX. It does the following: </para>
<orderedlist>
<listitem><para>creates a new URLClassLoader, whose parent is the current
context classloader </para></listitem>
<listitem><para>all files under ../lib and ../lib/ext are added to this
URLClassLoader (PENDING: really all files or only jars) </para></listitem>
<listitem><para>the context class loader is set to this URLClassLoader
</para></listitem>
<listitem><para>the class com.dreambean.ejx.editor.EJX is instantiated using
the new context class loader (ie the URLClassLoader) </para></listitem>
</orderedlist>
<para>
All plugins you would like to show in the EJX framework must be under ../lib or
../lib/ext, so that their classes can be loaded through the
context class loader. If this is not the case, your plugin is not even shown in the
EJX first window, where you can choose, among the
available plugins, which one you want to use.</para>
<para>
Every EJX plugin is archived in a jar and must have an entry in the manifest file
that reads:</para>
<para>
EJX-plugin: <![CDATA[<factory-class-name>]]></para>
<para>
where <![CDATA[<factory-class-name>]]> is the fully qualified name of the
ResourceManagerFactory implementation that can instantiate the
ResourceManager implementation for that plugin.</para>
</section>
<section><title>The bean context framework</title>
<para>
Following the Glasgow specification, JavaBeans can be logically grouped in
containers, called BeanContext. A BeanContext can
contain other nested BeanContext, or directly BeanContextChild JavaBeans. While
normal JavaBeans can be added to BeanContexts,
to obtain the full potentiality of the new framework, they should implement the
BeanContextChild interface. A BeanContextChild is
normally a terminal child of the containment hierarchy, so it cannot have nested
JavaBeans. JavaBeans, being they BeanContext or
BeanContextChild can be added to or removed from a BeanContext, and notification of
these events is delivered to registered
membership listeners.</para>
<para>
A BeanContext can expose services to its children, services that can easily accessed
by them simply specifying the interface that
represent the wanted service. The interfaces that provides this support are
BeanContextServices and BeanContextServiceProvider.</para>
<para>
BeanContextServices is a BeanContext with the possibility to be queried for services
that it hosts. BeanContextServiceProvider is the
service hosted by a BeanContextServices. Services can be added or removed from a
BeanContextServices, and notification of these
events is delivered to registered service listeners.</para>
<para>
Within this framework, JavaBeans can obtain a reference to the BeanContext in which
they are hosted and thus be aware of the
environment in which they're running; plus they can query the BeanContext for
services, if the BeanContext hosting them is a
BeanContextServices. If this BeanContextServices does not have the requested
service, the request goes up in the hierarchy, eventually
finding the BeanContextServices that provides the service.</para>
</section>
<section><title>The bean context root and the services</title>
<para>
As you may have guessed, com.dreambean.ejx.editor.EJX is a BeanContextServices
instance, and is the root of the bean context
hierarchy of the application.</para>
<para>
It hosts 2 services: </para>
<orderedlist>
<listitem><para>a Preference service, used to store user preferences like
screen size </para></listitem>
<listitem><para>an XMLManager service, used to allow JavaBeans to read from /
write to XML files.</para></listitem>
</orderedlist>
<para>
Direct children EJX are the plugins, that implements the ResourceManager interface.
ResourceManager extends BeanContextChild so
that implementors can be directly plugged in the containment hierarchy, but normally
implementors of the ResourceManager interface
implements BeanContextServices, to provide plugin-specific services to their nested
JavaBeans.</para>
<para>
PENDING: add a figure / schema of the containment tree with different colors
representing services</para>
</section>
<section><title>Where the GUI comes in ?</title>
<para>
We saw the bean context hierarchy, but what you can see on the screen is not totally
related to it (though there is a relationship). How
can EJX show the GUI for JavaBeans component seamlessly ?</para>
<para>
Every JavaBean that wants to display a GUI in EJX must implement either
BeanContextContainerProxy or
BeanContextChildComponentProxy. </para>
<para>
com.dreambean.ejx.editor.EJX implements BeanContextContainerProxy and its
getContainer() method expose a JDesktopPane of a
JFrame (also held by com.dreambean.ejx.editor.EJX [NOTE: this JFrame is not exposed
(as of 15 Nov 2000), so it is not accessible from
nested JavaBeans if they want play with the menu bar. I have in mind to change this
and indirectly expose the JFrame as a EJX
service]).</para>
<para>
JDesktopPane is the specialized class that hosts JInternalFrames. Normally plugins
implement the BeanContextChildComponentProxy
interface returning a java.awt.Component (subclass) that can be added to a
JInternalFrame and finally added to the JDesktopPane.</para>
<para>
The difference between BeanContextChildComponentProxy and BeanContextContainerProxy
is that the former is implemented by
JavaBeans whose enclosing BeanContext is responsible to call getComponent and add
the resulting java.awt.Component to some
existing GUI, while the latter is implemented by JavaBeans whose enclosed JavaBeans
are responsible to call getContainer() and add to
this java.awt.Container GUI components taken from somewhere else. The former says "I
know my children, let's take their GUI
components and add them here", the latter says "I know my parent, let's add this GUI
components to its GUI container".</para>
</section>
<section id="ejx2"><title>Getting strted with EJX</title>
<section><title>Introduction</title>
<para>
EJX/AWT written by Rickard �berg</para>
<para>
Both packages are created by Rickard �berg and are available at his
DreamBean Website: www.dreambean.com.
Both packages are heavily used in jBoss do create/maintain EJB descriptor
and other XML files.
The reason or motivation for me to write this HowTo was that I struggle to
understand EJX and AWT. On the
other hand Rickard was so busy with other stuff that I had to dig throug
myself and to save time for other
members of jBoss I started writing this HowTo. This document is still under
construction and will maybe never
be finished. </para>
<para> Idea of EJX</para>
<para>
EJX is a package and runtime environment enabling you to create a plugin to
add new functionality and new GUI
elements. EJX will dynamically lookup for plugins on the predefined package
/lib/ext and load them for you.
Whenever you create a new file or open a given file it will instantiate
your plugin and show as an Frame within
the EJX framework.
EJX uses XML but at the moment this is not quite clear for me but I am
working on it (AS 9/15/00), </para>
<para>
Idea of AWT</para>
<para>
AWT (or here called Advanced Window Toolkit and do not mix it up with
java.awt.*) enables you to use an
uniform GUI Environment and to use BeanContext with an easy to write XML
definition file.
I am still at the beginning to understand AWT and EJX but I will upgrade
this document as soon as I have more
information and examples. </para>
</section>
<section><title>Project</title>
<section><title>Introduction</title>
<para>
Based on the first draft of this document I separated the core EJX stuff from
the EJX examples to make it a little bit more
clear. Afterwards I implemented these changes in the EJX module of jBoss CVS
server. If you now download the EJX
module you can create a slim release of EJX without the examples. If you need
them you can just jump to the examples
directory and build the example from there (one by one) and only the examples
you want or need. </para>
</section>
<section><title>Structure</title>
<para>
To go through this document download the EJX module from the jBoss CVS server.
Attention: Before you start with compiling any examples you have to run the
compilation of the core project first. For this
go to the "ejx/src/build" and start the build.bat file. This compiles the core
project, copies the necessary jar-files to the
right place and creates the necessary ejxeditor.jar file.
Now you are ready for the examples. </para>
</section>
<section><title>Plain Pane Example</title>
<para>
This example can be found under "ejx/examples/plain.pane".
This was my first example and the goal was to creat a Panel within EJX
framework to display just a simple text. I used
this example to find simplest example within EJX.
According to the EJX spec the only necessary thing you have to to is: </para>
<orderedlist>
<listitem><para>Create a class extending the
com.dreambean.ejx.FileManagerFactory interface </para></listitem>
<listitem><para>Create a class extending the
com.dreambean.ejx.FileManager interface</para></listitem>
<listitem><para>Create an appropriate Manifest file with looks like
this for this example:
Class-Path: awt.jar ejb.jar EJX-plugin:
com.madplanet.plainPane.FileManagerFactoryImpl Name:
com/madplanet/plainPane/ Specification-Title: PlanePane
0.1 Specification-Version: v0.1 Specification-Vendor: MAD
plaNET plc Implementation-Title: ejx-plain-pane
Implementation-Version: build1 Implementation-Vendor: MAD
plaNET plc
</para></listitem>
<listitem><para>Compile these two classes </para></listitem>
<listitem><para>Put these two classes and the Manifest file into a
jar-file (name does not matter but I always name
it this way: ejx.<![CDATA[<ProjectName>]]>.jar).</para></listitem>
<listitem><para>And last but not least the just created jar-file into
the ejx/dist/lib/ext directory. </para></listitem>
</orderedlist>
<para>
Now the only thing left is to start EJX (go to ejx/dist/bin directory and
start EJX with "java -jar ejx.jar"). When the EJX
Frame comes up go to file/new and select "Plain Pane XML" and you will see our
plugin coming up.
Now let's have a closer look to the classes we created in our plugin.</para>
</section>
<section><title>FileManagerFactoryImpl</title>
<para>
Implements the com.dreambean.ejx.FileManagerFactory and enables the EJX
framework to select the right file for you.
But now let's delf into the code </para>
<para>
Classes to be imported </para>
<programlisting>
import java.io.File;
import javax.swing.filechooser.FileFilter;
import com.dreambean.ejx.FileManager;
import com.dreambean.ejx.FileManagerFactory;
</programlisting>
<para>
Class definition (to extend this class from FileFilter is just
convenience because it is needed either
way):</para>
<programlisting>
public class FileManagerFactoryImpl extends FileFilter
implements FileManagerFactory </programlisting>
<para>
These methods must be implement due FileManagerFactory interface.
The first method creates the
FileManager when a file is selected or in a given directory a new
one can be created. The second
method returns a FileFilter to select a file or directory and the
last is used to get a name for the
Plugin to select the right one. </para>
<programlisting>
public FileManager createFileManager() {
return new FileManagerImpl( this );
}
public FileFilter getFileFilter() {
return this;
}
public String toString(){
return "Plain Pane XML";
}
</programlisting>
</section>
<section><title>FileManagerImpl</title>
<para>
Implements the com.dreambean.ejx.FileManager and enables the plugin to decide
what GUI element to display. For each
file or directory selected a new instance of this class is created. </para>
<para>
Classes to be imported </para>
<programlisting>
import java.awt.BorderLayout;
import java.awt.Component;
import java.beans.beancontext.BeanContextServicesSupport;
import java.io.File;
import javax.swing.JPanel;
import javax.swing.JLabel;
import com.dreambean.ejx.FileManager;
import com.dreambean.ejx.FileManagerFactory;
</programlisting>
<para>
I am only so pitty about what classes are imported to show you at
the header where the used
classes are coming from.
Constructor of the class: </para>
<programlisting>
FileManagerImpl( FileManagerFactory pCaller ) {
mFactory = pCaller;
}
</programlisting>
<para>
Methods must be overwriten by the class, The important part is the
getComponent() method which
is called by the EJX framework to get the GUI component to be
displayed. </para>
<programlisting> <![CDATA[
public boolean isChanged() {
return true;
}
public void createNew() {
}
public void load( File file ) throws Exception {
}
public void save( File f ) throws Exception{
}
public File getFile() {
return null;
}
public void setFile( File pFile ) {
}
public FileManagerFactory getFactory() {
return mFactory;
}
public Component getComponent() {
JPanel lPane = new JPanel( new BorderLayout()
);
lPane.add( new JLabel(
"<HTML><BODY><H1>Hello World</H1>"
+ "<H2>Next Step</H2></BODY></HTML>" ),
BorderLayout.CENTER );
return lPane;
}
]]></programlisting>
</section>
<section><title>Simple Component Example</title>
<para>
This example can be found under "ejx/examples/simple.component".
This example is an introduction to AWT and how it can be used to define a GUI
by the XML description file, compiled and
display on the Panel in the EJX framework. To shorten the further discussion I
only show the important stuff having
changed or is new. </para>
<para>
The only thing with AWT you have to consider is that you have to use XMLBeans
to compile the BeanInfo XML
description into a Java class and then to compile it to a java bytecode class.
For that have a look at the build.xml and look
for xmlbeans. </para>
<para>
According to the AWT spec the only necessary thing you have to to is:</para>
<orderedlist>
<listitem><para>Create an Bean Info XML description file like this:
<![CDATA[
<bean class="com.madplanet.simpleComponent.MainPane"
displayname="Simple Component's Main Pane"
iconcolor16="/images/container.gif"> <property
name="FirstProperty" class="java.lang.String"
displayname="First Property"/> <property
name="SecondProperty" class="java.lang.String"
displayname="Second Property"/> ]]>
</para></listitem>
<listitem><para>Create a GUI component class and add the
GenericCustomizer to it (as parameter you have to
pass the class instance which is referred above (here it is
com.madplanet.singleComponent.MainPane). There are other classes
you can use but at the
moment I have no more informations. </para></listitem>
<listitem><para>Compile all the java classes</para></listitem>
<listitem><para>User XMLBeans to create the java sourcecode from the
XML beaninfo. The newly created java
classes are named like the referred class but with Beaninfo at the
end (same package structure). </para></listitem>
<listitem><para>Compile the bean info java sourcecode files.
</para></listitem>
</orderedlist>
<para>
That's it. </para>
</section>
<section><title>FileManagerImpl</title>
<para>Like the one before except the getComponent() method: </para>
<programlisting>
public Component getComponent() { // Create the Property Container and
return its GUI component return new MainPane().getComponent();
}
</programlisting>
</section>
<section><title>MainPane</title>
<para> This class now creates the GUI component using AWT to display the
properties this class have.</para>
<para>
Classes to be imported </para>
<programlisting>
import java.awt.BorderLayout;
import java.awt.Component;
import java.beans.beancontext.BeanContextSupport;
import
java.beans.beancontext.BeanContextChildComponentProxy;
import javax.swing.JPanel;
import com.dreambean.awt.GenericCustomizer;
</programlisting>
<para>
This class has to supclass the BeanContextSupport </para>
<programlisting>
public class MainPane extends BeanContextSupport
</programlisting>
<para>
There are the properties the Main Pane offer and which can then be
set by GUI component defined
by the Bean Context Attention: All the properties in the BeanInfo
XML file need here a public
getter and setter method with the appropriate type. </para>
<programlisting>
public String getFirstProperty() {
return mFirstProperty;
}
public void setFirstProperty( String pToSet ) {
mFirstProperty = pToSet;
}
public String getSecondProperty() {
return mSecondProperty;
}
public void setSecondProperty( String pToSet ) {
mSecondProperty = pToSet;
}
</programlisting>
<para>
This method returns the GUI component which contains the Generic
Customizer need to display
the properties of this instance accordingly to the Bean Info XML
description mentioned above.</para>
<programlisting>
public Component getComponent() {
JPanel lPane = new JPanel( new BorderLayout()
);
lPane.add( new GenericCustomizer( this ),
BorderLayout.CENTER );
return lPane;
}
</programlisting>
<para>
Eh voil�, that's it. When you build this example, start EJX and select Simple
Component XML you will see two lines with
the tag "First Property" and a Text Field (and also for Second
Property).</para>
<para>
That's all for now. In the next step I will delf further into AWT and how you
can use the Bean Info XML description to
describe more advanced application. In addition I will then use the save() and
load() method to load XML files which are
the persistent part of a plugin. </para>
<para>
I anything is wrong or not correct please contact me at
[EMAIL PROTECTED] Also if you want to know more in
detail or have a request for changes in this HowTo document. </para>
</section>
</section>
</section>
<section id="ejx3"><title>EJX/AWT GUI Basics HowTo</title>
<section><title>Introduction</title>
<para>
In this How To I will discuss the use of the BeanContext und AWT to create
GUIs and GUI components within
EJX but you can also use AWT outside of EJX.Attention: please note that I
always mean Rickard �berg's AWT
and not the Java AWT!</para>
<para>The AWT provides you with the following opportunities: </para>
<orderedlist>
<listitem><para>Customizers for your Beans</para></listitem>
<listitem><para>Property Editors to edit or select
properties</para></listitem>
</orderedlist>
<para>
This seems to be simple but combining them together with the Java Bean
Support and ordinary Swing coding
leads to advanced GUIs like the actual version of EJX used in jBoss (I am not
taking about the lack of User
guidance but about the abilities of the GUI to display and edit the data).
</para>
<para>
My biggest problem to understand EJX/AWT was that you have to deal with EJX,
AWT, Java Bean Support,
XML and Swing coding. Therefore I started from the simplest example to
understand each component, its
function and how to use it. In the "Getting-Started" How To I showed how to
create an EJX plugin and then
create a basic Bean GUI. Now I go a step further to dynamically manage GUI
components, use of more BeanInfo
features and to edit properties with the AWT property editors. So let's start
it! </para>
</section>
<section><title>
Tabbed Panes and Editors</title>
<section><title>Goals</title>
<para>
From the last example of the first How To create and remove GUI Components
(Tabbed Panes) dynamically and
edit the properties of the data instance with the AWT editors. </para>
</section>
<section><title>Design</title>
<para>
First of all I want correct I mistake in the previous example. In the
MainPane class it is said that getComponent()
is implemented because of BeanContextChildComponentProxy which is not
implemented in the class but it works
because the caller does not relay on this fact. But in this example I fixed
this. The question but still remains why
it should (will maybe be explained later). </para>
<para>
This example is really not a good example how to use EJX but it shows how to
use EJX/AWT. The idea is to use
a tabbed pane to display different views in our EJX frame. In addition the
user can create and remove the tabbed
pane as long as there is at least one left. And last but not least the user
should be able to select a value through
an editor instead of a plain input field. </para>
<para>
As we saw in the last example the initial GUI component to show the plugin is
created in the ResourceManager
on the getComponent() call which is called by the BeanContext structure we
use. But instead of create a Panel
which just keeps the GUI of the plugin we create now a viewer of the plugin
to display itself. This makes the
design more flexible because it is now defined in the Viewer instead of the
ResourceManager where it does not
belong. Now the viewer is an inner class because it is so closely related to
its outer component that it makes
sense to be there. </para>
<para>
The construct following is a little bit ugly and should not be MADE this way
but it is enough for us.
The ResourceManager getComponent() now calls the MainPane's getComponent()
method and this instantiate its
viewer and returns this Viewer as the GUI component to be shown. </para>
<para>
When the users now hits the create a new Tab or remove this tab the
appropriate method is called (by the
BeanContext) and it will create a new MainPane instance and adds its also
created Viewer instance as a new
Tab to the tabbed pan or remove the actual shown tab from the tabbed pane.
As you can see above the buttons we have a text input field and a drop down
box letting the user select between
two items. Both are AWT editors. </para>
</section>
<section><title>Implementation</title>
<para>
First lets have a look at the changes in the ResourceManager where the
getComponent() just instanciate the
MainPane and returns its GUI component.</para>
<programlisting>
public Component getComponent() {
// Create the Property Container and return its GUI component
return new MainPane().getComponent();
}
</programlisting>
<para>
Now let's look at the new BeanInfo description of the MainPane: </para>
<programlisting><![CDATA[
<bean class="com.madplanet.tabbedEditor.MainPane"
displayname="Tab Pane and Editor's Main Pane"
iconcolor16="/images/container.gif"> <property
name="FirstProperty" class="java.lang.String"
displayname="First Property"
propertyeditor="com.dreambean.awt.editors.TextEditor"/>
<property name="SecondProperty"
class="java.lang.String" displayname="Second
Property"
propertyeditor="com.madplanet.tabbedEditor.editors.SecondPropertyEditor"/>
<method name="createTab" displayname="Create a new
Tab"> <parameter displayname="Title"/> </method>
<method name="removeTab" displayname="Remove this
Tab"> </method> </bean>
]]></programlisting>
<para>
As you can see there are property editors settings for the first and second
property and the second
property uses its own editors. In addition you have methods listed which
appears as buttons in the
GUI because we use the GenericCustomizer. </para>
<para>
The new editor is just a simple subclass of the AWT TagsEditor defining what
items it has to show and to what
value the item relate to (you can use any Java Object you like): </para>
<programlisting>
package com.madplanet.tabbedEditor.editors;
import com.dreambean.awt.editors.TagsEditor;
/** * Editor to select the Second Property in a DD - editor */
public class SecondPropertyEditor extends TagsEditor
{ // Constructors
--------------------------------------------------
public SecondPropertyEditor() {
super(new String[] {"First Selection","Second Selection"},
new Object []{"First", "Second"});
}
} </programlisting>
<para>
And as "Grande Finale" we come to the heart of the plugin to the MainPane
class. </para>
<para>
The new viewer class is an inner class to the MainPane and creates a
GUI to display the
instance of its outer class instance. It keeps a list of outer class
instances to find the
index of the tab to be removed. The setObject() creates a new tab
and memorize the given
outer class. The removeTab() looks for the given outer instance and
removes its related
tab (by this index). </para>
<programlisting>
public class Viewer extends JTabbedPane implements Customizer
{ // Attributes
---------------------------------------------------
private Vector mDataObjectList = new Vector(); // Customizer
implementation
------------------------------------
public void setObject( Object pDataObject ) {
// Init UI
addTab( "Main", new GenericCustomizer( pDataObject ) );
mDataObjectList.addElement( pDataObject );
}
/** * Removes the given Tab with the given Data Object *
from the
Tabbed Pane * * @param pDataObject Tab with this Data
Object has to be removed if found **/
public void removeTab(Object pDataObject ) {
int lIndex = mDataObjectList.indexOf(
pDataObject );
if( lIndex >= 0 ) {
remove( lIndex );
mDataObjectList.removeElementAt( lIndex );
}
}
} </programlisting>
<para>
These are the new methods (already defined in the BeanInfo see
above) which are called if
the appropriate button is pressed. </para>
<programlisting>
public void createTab( String pTitle ) throws Exception {
System.out.println("Create new Tab with title: " + pTitle);
MainPane lNewPane = new MainPane();
lNewPane.mCustomizer = mCustomizer;
lNewPane.mCustomizer.setObject(
lNewPane );
}
public void removeTab() {
System.out.println( "Remove this tab");
( (Viewer) mCustomizer ).removeTab(this );
}
</programlisting>
</section>
</section>
<section><title> Remarks</title>
<para>
This is more ore less EJX and AWT. But it does not end here. The power of EJX
lays in the BeanContext and
how you combine EJX, BeanContext and AWT. You maybe think what's about XML
and we will come to XML
soon but (in my opinion) this is not a core part of EJX and AWT just use it
but just as the name of the EJX base
classes said they manage resources (or earlier just files). Therefore it must
be a way do deal with resources and
especially with XML resources. </para>
</section>
</section>
</section>
1.1 manual/src/docs/howtoj2eedeployer.xml
Index: howtoj2eedeployer.xml
===================================================================
<section><title>Deployment on JBoss</title>
<para>
Author:
<author><firstname>Daniel</firstname><surname>Schulze</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section>
<title>Introduction</title>
<para>
The application deployment on JBoss is managed by the J2eeDeployer MBean. The
J2eeDeployer is able
to deploy ejb.jar packages, webapplication.war packages and j2ee
application.ear packages.
Furthermore he is able to deploy unpacked ejb.jar files for development
purposes.
</para>
<para>
The deployment is url based, so it is possible to deploy from whatever source
as long as there is
a url handler for that source available in your environment.
(ie. http://somehost/applications/app.ear or
file:///home/user/development/myapp.ear)
</para>
</section>
<section>
<title>J2EE Deployer</title>
<para>
The J2eeDeployer currently provides 3 methods:
</para>
<itemizedlist>
<listitem>
<para>
void deploy (URL)
this method starts the deployment process for the application this URL points
to. The URL can be a
file: or a http:// or any other type of url your environment is capable to
handle. In case of
deploying a unpacked ejb.jar package the URL type is currently limited to file.
The deployment of an already deployed application (the name of the app is
significant) will result in an
undeployment of this app followed by a redeployment.
</para>
</listitem>
<listitem>
<para>
void undeploy (URL or Application name)
use this to undeploy an application. the parameter can be the URL that was
used to deploy this application or just the name (application name = file name
of the app package or directory name in case of unpacked) of the application.
</para>
</listitem>
<listitem>
<para>
boolean isDeployed (URL or Application name)
use this method to ask for the state of an application. The argument follows
the same rules as for the undeploy method.
</para>
</listitem>
</itemizedlist>
<para>
These 3 methods can be used via the web interface of JBoss at port 8082 at the
host JBoss is running on.
</para>
</section>
<section>
<title>The AutoDeployer as helper</title>
<para>
The AutoDeployer MBean is a helper for the J2eeDeployer to allow doing
administration smoothly via drag and drop
or to automate the redeployment in case of development. He observes the given
directories for changes and calls
the appropriate methods on the J2eeDeployer.
</para>
<para>
The AutoDeployer observes the timestamps of the application packages or the
timestamp of the META-INF/ejb-jar.xml
file in case of unpacked ejb.jar files.
</para>
<para>
The AutoDeployer is configured whether static by the MLET configuration or
dynamic by adding urls to watch for
in its web interface (port 8082 at the host JBoss is running on).
</para>
<para>
In its current version the AutoDeployer supports only local directories to
observe.
</para>
<para>
To deploy an ejb, web or ear package simply drop it in one of the observed
directories.
To autodeploy an unpacked ejb application, add the base directory of that
application
(base directory = the directory which containes the META-INF directory) to the
AutoDeployers
observed urls.
</para>
<para>
Note: There is still a misbehavior when the autodeployer thread wins the race
against the copy thread
which modifies a package!
</para>
</section>
<section>
<title>Creating J2EE applications</title>
<para>
j2ee applications or .ear files are jar archives containing a collection of
ejb, web, client, connector and/or
other library packages. Currently JBoss only supports ejb, web and other
library packages (client and connector
packages are ignored if present).
</para>
<para>
Other Library packages are class packages that are needed by your application
and are not provided by the j2ee
runtime environment (ie: some xml tools)
</para>
<para>
This document will only describe the JBoss relevant stuff in creating j2ee
packages for a detailed description
of how to build such applications see the J2EE specification under chapter 8!
</para>
<para>
First create all ejb, war and library archives you want to put together to
make up your application. Make sure
that all dependencies are solved, means: all classes that are needed by your
application must be contained in
your application (besides the classes that made up the J2EE platform (java
core, javax.transaction,
javax.sql, javax.servlet ...). Its up to you to create an arbitrary directory
structure for your application
to make it easier to maintain. Once you ve created your structure and moved
all files on their place you have
to create a deployment descriptor. This file must reside in the
<![CDATA[<your_app_dir>]]>/META-INF directory and must be
named application.xml.
</para>
<para>
Example:
the content of a simple application.xml file:
</para>
<programlisting><![CDATA[
<application>
<display-name>My Application</display-name>
<module>
<web>
<web-uri>web-app.war</web-uri>
<context-root>/myapp</context-root>
</web>
</module>
<module>
<ejb>ejb-app.jar</ejb>
</module>
</application>
]]></programlisting>
<para>
This descriptor describes an application that contains a web application
package (JSPs/Servlets/HTML) and an
ejb application (EJBs). The web applications war package is located at the
root of the .ear file and is named
web-app.war. It will be deployed under the webcontext /myapp. The ejb package
also resides in the applications
root directory and is called ejb-app.jar.
</para>
<para>
Understanding the shared classloader architecture in JBoss
</para>
<para>
When an application in JBoss gets deployed, every module will get deployed by
a separate container.
Every container will get its own classloader - this means that a call from one
module to an other must
be an remote call and all parameters must be serialized, because the classes
(even if they are loaded
from the same physical file) are not compatible across container boundaries.
To allow optimized
interaction across container boundaries (local calls with parameter ... per
reference) the classes
that are involved in this communication must be loaded by the same classloader.
</para>
<para>
In JBoss we achieve this issue with the following classloader architecture:
</para>
<para>
On deployment one - common - classloader is created. This classloader will get
all archives in its classpath
that are referenced (MANIFEST.MF/Class-Path)by any module contained in this
application.
</para>
<para>
When afterwards all modules become deployed in their containers, the
classloaders created by these containers
are all children of the common classloader.
</para>
<para>
Now on runtime the communication between modules across container
boundaries can be optimized when the classes used for the communication are
loaded by the common classloader.
</para>
<para>
example (continued):
To allow our previous mentioned simple example to make use of the
optimization, we must provide the classes the web
module needs to communicate with the ejb module in an separate third package,
lets call it ejb-client.jar.
This ejb-client.jar archive contains the remote interfaces of the ejbs and
special method parameter types that are
needed for the communication (if any). Now we put this package in the
directory /lib of our application.
</para>
<para>
To make sure that this package is now loaded by the common classloader, we
reference it from within the web
package by adding a Class-Path: entry to the web packages MANIFEST.MF file
that it looks something like that:
</para>
<literallayout>
<computeroutput>
Manifest-Version: 1.0
Class-Path: ./lib/ejb-client.jar
</computeroutput>
</literallayout>
<para>
Now you just jar your applications directory, name it
<![CDATA[<anyhow>]]>.ear, and drop it in one of JBoss'
autodeploy directories...
</para>
<para>
the content of our simple applications archive:
</para>
<literallayout> <computeroutput>
META-INF/
META-INF/MANIFEST.MF
META-INF/application.xml
ejb-app.jar
web-app.war
lib/
lib/ejb-client.jar
</computeroutput>
</literallayout>
</section>
</section>
1.1 manual/src/docs/howtojaas.xml
Index: howtojaas.xml
===================================================================
<section><title>JAAS Based Security in JBoss</title>
<para>
Author:
<author><firstname>Scott</firstname><surname>Stark</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<para>
<note><para>These instructions require a cvs snapshot that is latter than Jan 10
2001. The "JBoss-PRE2.1 with jetty 3.0.2" binary package
not work with these instructions as the configuration mechanism has changed since
the package was created. </para></note>
</para>
<para>
For a previous tutorial by Edward Kenworthy, see Security Walkthrough/How
To/Tutorial, first cut. The AppCallbackHandler implementation of
CallbackHandler in this document was derived from that tutorial. </para>
<section><title>Introduction</title>
<para>
This document describes the JBoss server's security architecture in some detail. It
should be sufficient to allow you to configure a simple security setup
for testing. It should also give you a good start to being able to inegrate your own
custom security implementation into JBoss. </para>
<itemizedlist>
<listitem><para><link linkend="jaas1">Security Model
Overview</link></para></listitem>
<listitem><para><link linkend="jaas2">How to Associate Security With the
Container SecurityInterceptor</link></para></listitem>
<listitem><para><link linkend="jaas3">Using
JaasSecurityManager</link></para></listitem>
<listitem><para><link linkend="jaas4">The Stateless Session
Bean</link></para></listitem>
<listitem><para><link linkend="jaas5">Deploying a Bean with
Security</link></para></listitem>
</itemizedlist>
</section>
<section id="jaas1"><title>Security Model Overview</title>
<para>
The security model in JBoss is based on the server container architecture's
pluggable method interceptors and the fact that the container factory always
inserts security interceptor(org.jboss.ejb.plugins.SecurityInterceptor). For a view
of see Entity Container Diagram for additional details. </para>
<para>
Integration of custom security requires implementing the two interfaces that the
SecurityInterceptor class uses to externalize its security checks. They
are:</para>
<programlisting>
package org.jboss.security;
public interface EJBSecurityManager
{
public boolean isValid(java.security.Principal principal, Object credential);
}
and:
package org.jboss.security;
public interface RealmMapping
{
public java.security.Principal getPrincipal(java.security.Principal principal);
public boolean doesUserHaveRole(java.security.Principal principal, Set
roleNames);
}
</programlisting>
<para>
JBoss includes a number of sample implementations of both interfaces. These can be
found in the org.jboss.security.plugins.samples package. There is
also a JMX service bean that can be used to setup a JAAS based implementation of
both interfaces. The JMX bean is
org.jboss.security.JaasSecurityManagerService and the security manager
implementation is org.jboss.security.JaasSecurityManager. This document
will focus on setting up the JaasSecurityManager via the JaasSecurityManagerService
for a trivial stateless session bean. Once you can perform the
steps documented to secure the example bean, you should be able to introduce your
own production ready security using this example as a template.
</para>
</section>
<section id="jaas2"><title>How to Associate Security With the Container
SecurityInterceptor</title>
<para>
Ok, so you know that every EJB container in JBoss includes a SecurityInterceptor
that delegates its security checks to an EJBSecurityManger and
RealmMapping implementation. Question: How do you choose which implementations a
given container uses? Answer: You specify this information via
the jboss deployment descriptor. </para>
<para>
The JBoss Deployment Descriptor(jboss.xml and standardjboss.xml)</para>
<para>
The JBoss deployment descriptor is the JBoss application specific deployment
configuration file. It describes optional behavior that is outside of the EJB
spec ejb-jar.xml deployment descriptor. The standardjboss.xml version of the file is
located in ${jboss_home}/conf/conf_name where ${jboss_home}
is the directory into which you have installed the JBoss distribution and conf_name
is the specific runtime configuration that you specify to the run.sh or
run.bat script when starting the server. The default value for conf_name is of
course "default". The standardjboss.xml specifies the global configuration
default values. You can also specific ejb-jar or j2ee-ear specific jboss.xml
descriptors that override specific configuration properties as appropriate for
your application. There are a quite a few configurable properties that can be set in
the file, but all are optional. For all of the possible configuration
elements and their details see the jboss.dtd. We are only concerned with the two
security specific elements: </para>
<itemizedlist>
<listitem><para>role-mapping-manager</para></listitem>
<listitem><para>authentication-module</para></listitem>
</itemizedlist>
<para>
role-mapping-manager
</para>
<para>
The role-mapping-manager element specifies the implementation of the
org.jboss.security.RealmMapping interface that is to be used by the container
SecurityInterceptor. The value is specified as the JNDI name to where the object is
located. Hence, the role-mapping-manager is like a JMS
TopicConnectionFactory in that it is accessed via a JNDI name. As far as the
container configuration is concerned, an implementation of
org.jboss.security.RealmMapping exists in the JBoss server JNDI namespace and
role-mapping-manager element provides the location. We'll se how
you get a RealmMapping instance into the JNDI namespace shortly. </para>
<para>
authentication-module
</para>
<para>
The authentication-module element specifies the implementation of the
org.jboss.security.EJBSecurityManager interface that is to be used by the
container SecurityInterceptor. The value is specified as the JNDI name to where the
object is located, just like the role-mapping-manager. </para>
<para>
Sample jboss.xml
The jboss.xml descriptor will we use is:
</para>
<programlisting><![CDATA[
<?xml version="1.0"?>
<jboss>
<container-configurations>
<container-configuration>
<container-name>Standard Stateless
SessionBean</container-name>
<role-mapping-manager>java:/jaas/other</role-mapping-manager>
<authentication-module>java:/jaas/other</authentication-module>
</container-configuration>
</container-configurations>
<enterprise-beans>
<session>
<ejb-name>StatelessSession</ejb-name>
<configuration-name>Standard Stateless
SessionBean</configuration-name>
</session>
</enterprise-beans>
</jboss>
]]></programlisting>
<para>
This says that we are augmenting the definition of the "Standard Stateless
SessionBean" container to include role-mapping-manager and
authentication-module security elements, the values of which are the JNDI name
"java:/jaas/other". We will see the reason for choosing this particular
name over the next couple of sections. The "Standard Stateless SessionBean" name is
coming from the standardjboss.xml default configuration file. </para>
<para>
Setting Up the RealmMapping and EJBSecurityManager in JNDI</para>
<para>
So the container configuration security elements specify the JNDI names where the
desired RealmMapping and EJBSecurityManager implementations
are to be obtained from for a given container. Now the question is how to bind
implementations into the JBoss server JNDI namespace. The answer is to
create a JMX mbean that creates and binds the desired implementations at server
startup. The JaasSecurityManagerService is an mbean that has been
written that we will use to perform the required setup. </para>
<para>
To configure the JaasSecurityManagerService, open the
${jboss_home}/conf/default/jboss.jcml file and look for an entry like: </para>
<programlisting><![CDATA[
<!-- JAAS security manager and realm mapping -->
<mbean code="org.jboss.security.plugins.JaasSecurityManagerService"
name="DefaultDomain:service=JaasSecurityManager" />
]]></programlisting>
<para>
If it is commented out or does not exist, uncomment or add the entry. The service
creates a reference to a JNDI Context at java:/jaas that lazily binds
instances of JaasSecurityManager under java:/jaas as requested. If you don't know
JNDI well or this just makes no sense, don't worry about. All we
care about is that with the JaasSecurityManagerService setup, any lookup on the
JBoss server JNDI InitialContext using a name of the form
java:/jaas/xyz results in an object of type
org.jboss.security.plugins.JaasSecurityManager that has the name xyz. Translated to
code, this means: </para>
<programlisting>
InitialContext ctx = new InitialContext();
JaasSecurityManager jsm1 = (JaasSecurityManager)
ctx.lookup("java:/jaas/xyz");</programlisting>
<para>
where jsm1 is an instance of JaasSecurityManager that was created using the name
"xyz". We are going to use this feature to bind a single instance of
JaasSecurityManager for use as both the RealmMapping and EJBSecurityManager
implementations(because JaasSecurityManager implements both
interfaces). We'll see this when we get to the session bean example. Now we need to
know how we can actually authenticate users and specify the
roles/identies they posses with a JaasSecurityManager.
</para>
</section>
<section id="jaas3"><title>Using JaasSecurityManager</title>
<para>
As you would expect, the JaasSecurityManager uses the JAAS (Java Authentication and
Authorization Service) to implement both the user
authentication and role mapping function of the RealmMapping and EJBSecurityManager
interfaces. It does this by creating a JAAS Subject using the
javax.security.auth.login.LoginContext mechanism. The JAAS Subject creation
involves:</para>
<programlisting>
Principal principal = ... passed in by SecurityInterceptor;
char[] password = ... passed in by SecurityInterceptor;
String name = ... the xyz component of java:/jaas/xyz used in the
authentication-module and role-mapping-manager
LoginContext lc = new LoginContext(name, new CallbackHandler(){...});
lc.login(); // This validates principal, password
Subject subject = lc.getSubject();
Set roles = subject.getPrincipals();
</programlisting>
<para>
If you know JAAS, you'll see that the name that was used in the creation of the
JaasSecurityManager correlates with the LoginContext Configuration
index. The JAAS LoginContext object looks to a configuration file that is made up of
named sections that describe the LoginModules that need to be
executed in order to perform authentication. This abstraction allows the
authentication api to be independent of a particular implementation. The
authentication of users and the assignment of user roles comes down to implementing
a javax.security.auth.spi.LoginModule and creating login
configuration entry that correlates with the JaasSecurityManager name. There exist a
number of sample LoginModule implementation in the
org.jboss.security.plugins.samples package. We are going to use the
JaasServerLoginModule to demonstrate the how to configure a LoginModule to
work with the JaasSecurityManager. If you need different authentication and role
mapping you can choose another LoginModule or implement you own
and then configure it using the same steps we will use. </para>
<para>
Using JaasServerLoginModule
</para>
<para>
The JaasServerLoginModule class is a simple file based implemention that uses two
files(users.properties and roles.properities) to perform
authentication and role mapping respectively. </para>
<para>
users.properties</para>
<para>
The users.properties file is a java properties formatted file that specifies the
username to password mapping. Its format is
username1=password1
username2=password2
...
with one entry per line.
</para>
<para>
roles.properties
</para>
<para>
The roles.properties file is a java properties formatted file that specifies the
username to role(s) mapping. Its format is
username1=role1[,role2,...]
username2=role1
...
with one entry per line. If a user has multiple roles they are specified using a
comma separated list. </para>
<para>
The LoginModule Configuration File
</para>
<para>
The JAAS LoginModule Configuration file is ${jboss_home)/conf/default/auth.conf. The
syntax is: </para>
<programlisting>
name {
login_module_class_name (required|optional|...) [options];
};
See the JAAS documentation for the complete syntax description. There should be an
entry like the following: // The default server login module
other {
// A realistic server login module, which can be used when the number
// of users is relatively small. It uses two properties files:
// users.properties, which holds users (key) and their password (value).
// roles.properties, which holds users (key) and a comma-separated list of
their roles (value).
org.jboss.security.plugins.samples.JaasServerLoginModule required;
};
</programlisting>
<para>
This indicates that the JaasServerLoginModule we want to use is setup for the
"other" configuration. This happens to the the configuration that JAAS
uses when it can't find a match and it will work fine for us. </para>
<para>
We have touched on all of the JBoss security related elements we need to configure.
Let's now put together a simple session bean that we will secure to
demonstrate how to use what we have gone over to deploy a secure bean. </para>
</section>
<section id="jaas4"><title>The Stateless Session Bean</title>
<para>
Here are the home, remote and bean classes for the simple stateless session bean we
are going to secure, along with a simple client that creates an
instance of the session bean:</para>
<para>
StatelessSession.java</para>
<programlisting>
import javax.ejb.*;
import java.rmi.*;
public interface StatelessSession extends EJBObject
{
public String echo(String arg) throws RemoteException;
}
StatelessSessionHome.java
import javax.ejb.*;
import java.rmi.*;
public interface StatelessSessionHome extends EJBHome
{
public StatelessSession create() throws RemoteException, CreateException;
}
StatelessSessionBean.java
import java.rmi.RemoteException;
import java.security.Principal;
import javax.ejb.*;
public class StatelessSessionBean implements SessionBean
{
private SessionContext sessionContext;
public void ejbCreate() throws RemoteException, CreateException
{
System.out.println("StatelessSessionBean.ejbCreate() called");
}
public void ejbActivate() throws RemoteException
{
System.out.println("StatelessSessionBean.ejbActivate() called");
}
public void ejbPassivate() throws RemoteException
{
System.out.println("StatelessSessionBean.ejbPassivate() called");
}
public void ejbRemove() throws RemoteException
{
System.out.println("StatelessSessionBean.ejbRemove() called");
}
public void setSessionContext(SessionContext context) throws RemoteException
{
sessionContext = context;
}
public String echo(String arg)
{
System.out.println("StatelessSessionBean.echo, arg="+arg);
Principal p = sessionContext.getCallerPrincipal();
System.out.println("StatelessSessionBean.echo, callerPrincipal="+p);
return arg;
}
}
</programlisting>
<para>ejb-jar.xml</para>
<programlisting><![CDATA[
<?xml version="1.0"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans
1.1//EN"
"http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">
<ejb-jar>
<display-name>SecurityTests</display-name>
<enterprise-beans>
<session>
<description>A trival echo bean</description>
<ejb-name>StatelessSession</ejb-name>
<home>StatelessSessionHome</home>
<remote>StatelessSession</remote>
<ejb-class>StatelessSessionBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<security-role>
<role-name>Echo</role-name>
</security-role>
<method-permission>
<role-name>Echo</role-name>
<method>
<ejb-name>StatelessSession</ejb-name>
<method-name>*</method-name>
</method>
</method-permission>
</assembly-descriptor>
</ejb-jar>
]]></programlisting>
<para>StatelessSessionClient.java</para>
<programlisting><![CDATA[
import java.io.IOException;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
/** Run with -Djava.security.auth.login.config=${jboss_home}/client/auth.conf
where ${jboss_home} is the location of your JBoss distribution.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class StatelessSessionClient
{
static class AppCallbackHandler implements CallbackHandler
{
private String username;
private char[] password;
public AppCallbackHandler(String username, char[] password)
{
this.username = username;
this.password = password;
}
public void handle(Callback[] callbacks) throws
java.io.IOException, UnsupportedCallbackException
{
for (int i = 0; i < callbacks.length; i++)
{
if (callbacks[i] instanceof NameCallback)
{
NameCallback nc = (NameCallback)callbacks[i];
nc.setName(username);
}
else if (callbacks[i] instanceof PasswordCallback)
{
PasswordCallback pc = (PasswordCallback)callbacks[i];
pc.setPassword(password);
}
else
{
throw new UnsupportedCallbackException(callbacks[i],
"Unrecognized Callback");
}
}
}
}
public static void main(String args[]) throws Exception
{
try
{
if( args.length != 2 )
throw new IllegalArgumentException("Usage: username password");
String name = args[0];
char[] password = args[1].toCharArray();
AppCallbackHandler handler = new AppCallbackHandler(name, password);
LoginContext lc = new LoginContext("TestClient", handler);
System.out.println("Created LoginContext");
lc.login();
}
catch (LoginException le)
{
System.out.println("Login failed");
le.printStackTrace();
}
try
{
InitialContext jndiContext = new InitialContext();
StatelessSessionHome home = (StatelessSessionHome)
jndiContext.lookup("StatelessSession");
System.out.println("Found StatelessSessionHome");
StatelessSession bean = home.create();
System.out.println("Created StatelessSession");
System.out.println("Bean.echo('Hello') -> "+bean.echo("Hello"));
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
]]></programlisting>
<para>
The session bean is trivial. The client is also trivial except for the use of a JAAS
LoginContext and CallbackHandler implementation. This is how a client
establishes the username and password that is sent to jboss. Now, finally let's put
everything together and deploy the session bean. </para>
</section>
<section id="jaas5"><title>Deploying a Bean with Security</title>
<para>
We will perform the following steps to deploy and test the secured session bean:
</para>
<orderedlist>
<listitem><para>Compile the session bean and client </para></listitem>
<listitem><para>Create the session bean ejb-jar with the ejb-jar.xml and
jboss.xml security elements </para></listitem>
<listitem><para>Edit the users.properties and roles.properties </para></listitem>
<listitem><para>Deploy the session bean jar, users.properties and
roles.properties </para></listitem>
<listitem><para>Edit the JBoss server jboss.jcml and auth.conf files
</para></listitem>
<listitem><para>Start the JBoss server </para></listitem>
<listitem><para>Setup client env and test access to the session bean
</para></listitem>
</orderedlist>
<para>
Compile the session bean and client
</para>
<para>
The examples I'll go through are on a windows 2000 box using the cygwin port of the
GNU tools. So most things will look like unix with the exception of
the ';' path separator used in the java classpath. </para>
<para>
First save all of the files presented in this document. You should have the
following 6 files: </para>
<literallayout>
<command>
bash 1066>ls
StatelessSession.java StatelessSessionHome.java
StatelessSessionBean.java ejb-jar.xml
StatelessSessionClient.java jboss.xml
</command></literallayout>
<para>
Next, setup the classpath as follows by substituting the value for jboss_home
appropriate for your system. </para>
<literallayout><command>
bash 1068>export CLASSPATH="${jboss_home}/client/jaas.jar"
bash 1069>CLASSPATH="${CLASSPATH};${jboss_home}/client/ejb.jar"
bash 1070>CLASSPATH="${CLASSPATH};${jboss_home}/client/jnp-client.jar"
bash 1071>CLASSPATH="${CLASSPATH};${jboss_home}/client/jboss-client.jar"
bash 1072>CLASSPATH="${CLASSPATH};."
bash 1073>echo $CLASSPATH
D:/usr/local/src/cvsroot/jBoss/jboss/dist/client/jaas.jar;D:/usr/local/src/cvsroot/jBoss/jboss/dist/client/ejb.jar;\
D:/usr/local/src/cvsroot/jBoss/jboss/dist/client/jnp-client.jar;D:/usr/local/src/cvsroot/jBoss/jboss/dist/client/jboss-client.jar;.
</command></literallayout>
<para>
Next, compile all of the source. </para>
<literallayout><command>
bash 1077>javac -g *.java
bash 1078>ls
StatelessSession.class
StatelessSession.java
StatelessSessionBean.class
StatelessSessionBean.java
StatelessSessionClient$AppCallbackHandler.class
StatelessSessionClient.class
StatelessSessionClient.java
StatelessSessionHome.class
StatelessSessionHome.java
ejb-jar.xml
jboss.xml
</command></literallayout>
<para>
Create the session bean ejb-jar with the ejb-jar.xml and jboss.xml security
elements</para>
<para>
Next, create the session bean jar as follows: </para>
<literallayout><command>
bash 1087>jar -cf $jboss_home/deploy/ssbean.jar StatelessSession.class
StatelessSessionBean.class StatelessSessionHome.class META-INF
bash 1087>jar -tf $jboss_home/deploy/ssbean.jar
META-INF/
META-INF/MANIFEST.MF
StatelessSession.class
StatelessSessionBean.class
StatelessSessionHome.class
META-INF/ejb-jar.xml
META-INF/jboss.xml
</command></literallayout>
<para>
Edit the users.properties and roles.properties</para>
<para>
Create a users.properties and roles.properties with the following data in each file:
</para>
<literallayout>
<command>
bash 1090>cat users.properties
scott=echoman
stark=javaman
bash 1091>cat roles.properties
scott=Echo
stark=Java,Coder
bash 1092>
</command></literallayout>
<para>
Deploy the session bean jar, users.properties and roles.properties </para>
<para>
We already deployed the session bean jar by jaring the files to the
$jboss_home/deploy directory. To deploy the users.properties and roles.properties
simply copy them to to the $jboss_home/conf/default directory. </para>
<para>
Edit the JBoss server jboss.jcml and auth.conf files</para>
<para>
These files needs to be setup as described earlier. The jboss.jcml file needs to
have the JaasSecurityManagerService mbean element:</para>
<programlisting><![CDATA[
...
<!-- JAAS security manager and realm mapping -->
<mbean code="org.jboss.security.plugins.JaasSecurityManagerService"
name="DefaultDomain:service=JaasSecurityManager" />
and the auth.conf needs to have the JaasServerLoginModule entry in the other
section:
...
// The default server login module
other {
// A realistic server login module, which can be used when the number
// of users is relatively small. It uses two properties files:
// users.properties, which holds users (key) and their password (value).
// roles.properties, which holds users (key) and a comma-separated list of
their roles (value).
org.jboss.security.plugins.samples.JaasServerLoginModule required;
// For database based authentication comment the line above,
// uncomment the line below and adjust the parameters in quotes
// Database server login module provides security manager only, no role mapping
// org.jboss.security.plugins.DatabaseServerLoginModule required
db="jdbc/DbJndiName"
table="UserTable" name="UserNameColumn" password="UserPswColumn";
};
]]></programlisting>
<para>
Start the JBoss server</para>
<para>
Go to the $jboss_home/bin and start the run.sh or run.bat script as appropriate for
you system. You will see a good deal of ouput on your console. Mine
looks like, and I have emphasized the session bean deployment output. </para>
<literallayout><computeroutput>
811>run.bat
Using configuration "default"
[Info] Java version: 1.3.0_01,Sun Microsystems Inc.
[Info] Java VM: Java HotSpot(TM) Client VM 1.3.0_01,Sun Microsystems Inc.
[Info] System: Windows 2000 5.0,x86
[Shutdown] Shutdown hook added
[Service Control] Registered with server
[Jetty] Setting unpackWars=false
[Jetty] Set successfully
[Jetty] Adding configuration: URL=file:/usr/local/src/cvsroot/jBoss/jboss/
dist/conf/default/jetty.xml
[Jetty] Added successfully
[Service Control] Initializing 18 MBeans
[Webserver] Initializing
[Webserver] Initialized
[Naming] Initializing
[Naming] Initialized
...
[J2EE Deployer Default] Starting
[J2EE Deployer Default] Cleaning up deployment directory
[J2EE Deployer Default] Started
[Auto deploy] Starting
[Auto deploy] Watching D:\usr\local\src\cvsroot\jBoss\jboss\dist\deploy
[Auto deploy] Auto deploy of
file:/D:/usr/local/src/cvsroot/jBoss/jboss/dist/deploy/ssbean.jar
[J2EE Deployer Default] Deploy J2EE application:
file:/D:/usr/local/src/cvsroot/jBoss/
jboss/dist/deploy/ssbean.jar
[J2EE Deployer Default] Create application ssbean.jar
[J2EE Deployer Default] install module ssbean.jar
[J2EE Deployer Default] Starting module ssbean.jar
[Container factory] Deploying:file:/D:/usr/local/src/cvsroot/
jBoss/jboss/dist/tmp/deploy/Default/ssbean.jar/ejb1001.jar
[Verifier] Verifying
file:/D:/usr/local/src/cvsroot/jBoss/jboss/dist/tmp/deploy/Default/ssbean.jar/ejb1001.jar
[Container factory] Deploying StatelessSession
[Container factory] Deployed application: file:/D:/usr/local/src/cvsroot/
jBoss/jboss/dist/tmp/deploy/Default/ssbean.jar/ejb1001.jar
[J2EE Deployer Default] J2EE application: file:/D:/usr/local/src/cvsroot/
jBoss/jboss/dist/deploy/ssbean.jar is deployed.
[Auto deploy] Started
[JMX RMI Adaptor] Starting
[JMX RMI Adaptor] Started
[JMX RMI Connector] Starting
[JMX RMI Connector] Started
[Service Control] Started 18 services
[Default] JBoss PRE-2.1 Started
</computeroutput></literallayout>
<para>
Setup client env and test access to the session bean</para>
<para>
At this point the session bean is deployed and it should only be accessible by users
with a role of 'Echo', and we have one user with a username 'scott'
and a password 'echoman' that has this role. We have another user with a username
'stark' and a password 'javaman' that should not be able to
acccess the session bean because he does not have the required role. Let's test
this. </para>
<para>
We need one final bit of information in order for the client to find the JBoss
server JNDI name service. Since we are using a no arg InitialContext in the
client, we need a jndi.properties file in our classpath(or we need to specify all
required properities on the command line). For JBoss, the jndi.properties
file should look like the following for the server running on the localhost with the
default name service port: </para>
<literallayout><computeroutput>
bash 1108>cat jndi.properties
# JNDI initial context properties for jboss app server
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost
java.naming.factory.url.pkgs=org.jboss.naming
</computeroutput>
</literallayout>
<para>
Create this file in the same directory as your StatelessSessionClient.java file
since this directory is on the classpath we setup earlier. Now, run the client
as user scott and specify the location of the JBoss client side JAAS login
configuration file as follows: </para>
<literallayout><computeroutput>
bash 1109>java
-Djava.security.auth.login.config=file://${jboss_home}/client/auth.conf
StatelessSessionClient scott echoman
Created LoginContext
Found StatelessSessionHome
Created StatelessSession
Bean.echo('Hello') -> Hello
--- Server console:
[StatelessSession] StatelessSessionBean.ejbCreate() called
[StatelessSession] StatelessSessionBean.echo, arg=Hello
[StatelessSession] StatelessSessionBean.echo, callerPrincipal=scott
</computeroutput></literallayout>
<para>
Ok, so that succeed as desired. Now we need to make sure that unauthorized users are
actually denied access. This time run as user stark:</para>
<literallayout><computeroutput>
bash 1111>java
-Djava.security.auth.login.config=file://${jboss_home}/client/auth.conf
StatelessSessionClient stark javaman
Created LoginContext
Found StatelessSessionHome
java.rmi.ServerException: RemoteException occurred in server thread; nested
exception is:
java.rmi.RemoteException: checkSecurityAssociation; nested exception is:
java.lang.SecurityException: Illegal access exception
java.rmi.RemoteException: checkSecurityAssociation; nested exception is:
java.lang.SecurityException: Illegal access exception
java.lang.SecurityException: Illegal access exception
at
sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:245)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:220)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:122)
at
org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker_Stub.invokeHome(Unknown Source)
at org.jboss.ejb.plugins.jrmp.interfaces.HomeProxy.invoke(HomeProxy.java:221)
at $Proxy0.create(Unknown Source)
at StatelessSessionClient.main(StatelessSessionClient.java:74)
--- Server console: No new output
</computeroutput></literallayout>
<para>
Alright, seems secure. Let's try user scott with an invalid password: </para>
<literallayout>
<computeroutput>
bash 1113>java
-Djava.security.auth.login.config=file://${jboss_home}/client/auth.conf
StatelessSessionClient scott badpass
Created LoginContext
Found StatelessSessionHome
java.rmi.ServerException: RemoteException occurred in server thread; nested
exception is:
java.rmi.RemoteException: checkSecurityAssociation; nested exception is:
java.lang.SecurityException: Authentication exception
java.rmi.RemoteException: checkSecurityAssociation; nested exception is:
java.lang.SecurityException: Authentication exception
java.lang.SecurityException: Authentication exception
at
sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:245)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:220)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:122)
at
org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker_Stub.invokeHome(Unknown Source)
at org.jboss.ejb.plugins.jrmp.interfaces.HomeProxy.invoke(HomeProxy.java:221)
at $Proxy0.create(Unknown Source)
at StatelessSessionClient.main(StatelessSessionClient.java:74)
--- Server console:
[JAASSecurity] Bad password.
[StatelessSession] javax.security.auth.login.FailedLoginException: Password
Incorrect/Password Required
[StatelessSession] at
org.jboss.security.plugins.AbstractServerLoginModule.login(AbstractServerLoginModule.java:110)
[StatelessSession] at
org.jboss.security.plugins.samples.JaasServerLoginModule.login(JaasServerLoginModule.java:94)
[StatelessSession] at java.lang.reflect.Method.invoke(Native Method)
[StatelessSession] at
javax.security.auth.login.LoginContext.invoke(LoginContext.java:595)
[StatelessSession] at
javax.security.auth.login.LoginContext.access$000(LoginContext.java:125)
[StatelessSession] at
javax.security.auth.login.LoginContext$3.run(LoginContext.java:531)
[StatelessSession] at java.security.AccessController.doPrivileged(Native Method)
[StatelessSession] at
javax.security.auth.login.LoginContext.invokeModule(LoginContext.java:528)
[StatelessSession] at
javax.security.auth.login.LoginContext.login(LoginContext.java:449)
[StatelessSession] at
org.jboss.security.plugins.JaasSecurityManager.authenticate(JaasSecurityManager.java:168)
[StatelessSession] at
org.jboss.security.plugins.JaasSecurityManager.isValid(JaasSecurityManager.java:101)
[StatelessSession] at
org.jboss.ejb.plugins.SecurityInterceptor.checkSecurityAssociation(SecurityInterceptor.java:101)
[StatelessSession] at
org.jboss.ejb.plugins.SecurityInterceptor.invokeHome(SecurityInterceptor.java:124)
[StatelessSession] at
org.jboss.ejb.plugins.LogInterceptor.invokeHome(LogInterceptor.java:106)
[StatelessSession] at
org.jboss.ejb.StatelessSessionContainer.invokeHome(StatelessSessionContainer.java:253)
[StatelessSession] at
org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker.invokeHome(JRMPContainerInvoker.java:347)
[StatelessSession] at java.lang.reflect.Method.invoke(Native Method)
[StatelessSession] at
sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:241)
[StatelessSession] at sun.rmi.transport.Transport$1.run(Transport.java:142)
[StatelessSession] at java.security.AccessController.doPrivileged(Native Method)
[StatelessSession] at
sun.rmi.transport.Transport.serviceCall(Transport.java:139)
[StatelessSession] at
sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:443)
[StatelessSession] at
sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:643)
[StatelessSession] at java.lang.Thread.run(Thread.java:484)
</computeroutput>
</literallayout>
<para>
Mission accomplished.
</para>
</section>
</section>
1.1 manual/src/docs/howtojavamail.xml
Index: howtojavamail.xml
===================================================================
<section><title>Using JavaMail in JBoss</title>
<para>
<author><firstname>Michel</firstname><surname>de Groot</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section><title>Introduction</title>
<para>
JBoss has a built-in implementation of the JavaMail API. You can use this
service from inside and outside EJBs. We
describe here how to use the service. </para>
</section>
<section><title>Installation <![CDATA[&]]> Configuration</title>
<orderedlist>
<listitem><para>Edit <![CDATA[conf/<yourconfig>/jboss.jcml]]> and find Mail
Service MBean (almost on the bottom).</para>
<para>
a) Replace the User and Password attributes values with the user name and
password used to connect to your
mail server. You can find these values in your mail program. The mail
service will use this account to send mails,
so be sure that this mail account works properly (test it with your mail
program for example).</para>
<para>
b) Replace the ConfigurationFile attribute value with the file containing
the mail settings. Default is
"mail.properties", which is also in the <![CDATA[conf/<yourconfig>]]>
directory. This file will be edited in step 2.</para>
<para>
c) Replace the JNDIName attribute value with the JNDI name for your mail
session. The default is "Mail". This
JNDI name will be used in jboss.xml to identify the resource. This is
explained in more detail in step 4.</para>
</listitem>
<listitem><para>Edit the mail properties file you identified in step 1b. By
default, this is <![CDATA[conf/<yourconfig>/mail.properties.]]></para>
<para>
Edit the following lines:
<programlisting>
mail.user = sa005697 // the user to connect with; same as in step 1a
mail.pop3.host = pop3.wolmail.nl // the pop host to store the mail
on
mail.smtp.host = smtp.wolmail.nl // the smtp host to send the mail
to
mail.from = [EMAIL PROTECTED] // the 'from' field that is
filled in by default in e-mails
</programlisting>
</para>
<para>
You can find most value in your mail program. You might want to inspect
the JavaMail specification for more
details.</para>
<para>
The last line, mail.debug, should be set to 'true' for now. This will
provide you with verbose debugging
information. Once you have everything running correctly, you can set it
to false.</para>
</listitem>
<listitem><para>Edit the ejb-jar.xml of the EJB that uses the mail service.
In your EJB, specify a<![CDATA[ <resource-ref> ]]>like this:
<programlisting><![CDATA[
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>Mailer</ejb-name>
<home>some.package.MailerHome</home>
<remote>some.package.Mailer</remote>
<ejb-class>some.package.MailerEJB</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<resource-ref>
<res-ref-name>mail/MyMail</res-ref-name>
<res-type>javax.mail.Session</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</session>
</enterprise-beans>
</ejb-jar>
]]></programlisting>
</para>
<para>
This will tell the EJB container that the EJB uses a javax.mail.Session
resource named mail/MyMail and that
authorization is container managed.</para>
<para>
You can change the name if you like, but be sure to use the same name in
step 6, in the code example. </para>
</listitem>
<listitem><para>Edit the jboss.xml of the EJB that uses the mail service.
If you don't have this file, create it and place it in the
same directory as the ejb-jar.xml of the EJB. This file is JBoss specific
and tells JBoss how to map the mail
resource to the mail service provider in JBoss.
In this file, specify a <![CDATA[ <resource-manager>]]> like this:
<programlisting><![CDATA[
<jboss>
<resource-managers>
<resource-manager>
<res-name>mail/MyMail</res-name>
<res-jndi-name>Mail</res-jndi-name>
</resource-manager>
</resource-managers>
</jboss>
]]></programlisting>
</para>
<para>
The name that you specify here is the name that you specified in step 3.
The JNDI name that you specify here is
the name that you specified in step 1c.</para>
</listitem>
<listitem><para>Edit the bin/run.bat file of your JBoss installation.
Include ../lib/ext/mail.jar and ../lib/ext/activation.jar in the
classpath explicitly. This assumes that you start JBoss from the bin
directory. If not, you should modify the paths
to the jars accordingly.</para>
<para>
TO BE IMPROVED: This step should not be required; both mail.jar and
activation.jar are correctly found during
the ClassPathExtension scan, but somehow their classes cannot be found
later. Maybe something missing in the
manifest.mf files? </para>
</listitem>
<listitem><para>Code example
This code example assumes that you are working from inside a JBoss
container. For example, this is the case if
the code is placed in a JBoss managed SessionBean.</para>
<para>
TO BE IMPROVED: This code example does not use PortableRemoteObject,
because I could not locate it
anywhere in the JBoss jars. The code will work without it on JBoss. It
should be used however to make the
code more portable. I'm also not sure what happens in a distributed JBoss
installation. </para>
<programlisting><![CDATA[
import java.util.Date;
import javax.ejb.SessionBean;
import javax.naming.InitialContext;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.InternetAddress;
import javax.mail.Transport;
import javax.mail.Address;
import javax.mail.Message;
//import javax.rmi.PortableRemoteObject;
public class SomeEJB implements SessionBean {
public void ejbCreate() {}
public void ejbPostCreate() {}
public void sendMails() throws java.rmi.RemoteException {
Session session = null;
try {
session = (Session)new
InitialContext().lookup("java:comp/env/mail/MyMail");
//session = (Session)PortableRemoteObject.narrow(
// new
InitialContext().lookup("java:comp/env/mail/MyMail"), Session.class);
} catch (javax.naming.NamingException e) {
e.printStackTrace();
}
try {
MimeMessage m = new MimeMessage(session);
m.setFrom();
Address[] to = new InternetAddress[] {new
InternetAddress("<your_email_adres@<your_provider>.<your_extension>");
m.setRecipients(Message.RecipientType.TO, to);
m.setSubject("JavaMail Test");
m.setSentDate(new Date());
m.setContent("Test from inside EJB Using JBoss",
"text/plain");
Transport.send(m);
} catch (javax.mail.MessagingException e) {
e.printStackTrace();
}
}
public void ejbActivate() {}
public void ejbPassivate() {}
public void ejbRemove() {}
public void setSessionContext(javax.ejb.SessionContext ec) {}
}
]]></programlisting>
</listitem>
<listitem><para>Using the JavaMail service with mail servers that require
POP authentication before SMTP
You can do this by using: </para>
<programlisting>
import javax.mail.Store;
Store s = session.getStore();
s.connect(); // POP authentication
Transport.send(m);
</programlisting>
</listitem>
</orderedlist>
</section>
</section>
1.1 manual/src/docs/howtojbuilderdebug.xml
Index: howtojbuilderdebug.xml
===================================================================
<section><title>How to Run JBoss in JBuilder's Debugger</title>
<section><title>JBuilder Foundation 3.5</title>
<para>
With each of these, replace <![CDATA[<JBOSS-HOME>]]> with the location of your JBoss
directory, for example, C:\jboss.</para>
<orderedlist>
<listitem><para>Launch JBuilder.</para></listitem>
<listitem><para>Go to Project|Properties, click the Paths tab, and make sure
you're using JDK 1.3 as your JDK. To have 1.3 available, you
may need to add it or change your default JDK. First install JDK 1.3 (from
Sun) on your PC, then point JBuilder to it by
clicking "new" or "edit" in the Select a JDK dialog.</para></listitem>
<listitem><para>On the Paths tab, go to the Required Libraries tab, click "add"
and then "new" to create a new one, and call it "JBoss Server"
(or something similar). Add the following .jar file:
<![CDATA[<JBOSS-HOME>]]>\bin\run.jar </para></listitem>
<listitem><para>Click OK on the Edit library dialog, then OK on the Select one
or more libraries dialog, which should add the new library to
your project. The library will now be available to other projects as
well.</para></listitem>
<listitem><para>Go to the Run tab of the Project Properties dialog. On the
Application tab, set the main class to org.jboss.Main. Note that this
is project-specific and will need to be done for each project running JBoss.
</para></listitem>
<listitem><para>On the Run tab, under "VM Parameters", add the following (again,
for each project):
-Duser.dir=<![CDATA[<JBOSS-HOME>]]> </para></listitem>
<listitem><para>Click OK and close JBuilder.</para></listitem>
<listitem><para>Create a copy of your JBuilder shortcut (in Win98, it should be
in C:\WINDOWS\Start Menu\Programs\JBuilder 3.5). Rename
the copy to something appropriate, such as "JBuilder with JBoss working
directory". </para></listitem>
<listitem><para>Edit the shortcut's properties by right-clicking and choosing
properties. Change the "Start in" folder to
<![CDATA[<JBOSS-HOME>]]>\bin\. Click OK. </para></listitem>
<listitem><para>To run or debug JBoss within JBuilder, first use the modified
shortcut to launch JBuilder, then open your project as normal and
select Run|Run Project or Run|Debug Project. </para></listitem>
<listitem><para>To debug EJBs within this setup, first build and deploy them in
<![CDATA[ <JBOSS-HOME>\deploy ]]> as you would normally. Then set
breakpoints in your EJB code and debug the project using org.jboss.Main as the
main class using the instructions above. </para></listitem>
</orderedlist>
<para>
NOTE: When running JBoss within JBuilder, it will launch an empty console window
with "java" as the title. I'm not sure why this is,
but it appears to have some relation to Hypersonic SQL. You will probably need to
close this window manually after stopping JBoss.
</para>
</section>
<section><title>JBuilder 4</title>
<para>
Author: Peter Henderson
</para>
<orderedlist>
<listitem><para>Project Properties. (Project properties/paths)
Set the working directory to the JBoss bin dir. For example:
C:/jboss_tomcat/jboss-2.0-FINAL/bin</para></listitem>
<listitem><para>Set VM parameters. (Project properties/run)
-classic -Dtomcat.home=C:\jboss_tomcat\tomcat-3.2-b7
-Duser.dir=C:\jboss_tomcat\jboss-2.0-FINAL/bin </para></listitem>
<listitem><para>Set Main class
Set main class to org.jboss.Main </para></listitem>
<listitem><para>Create a JBoss Server Library. (Project properties/required
libs) </para>
<para>Add: </para>
<programlisting>
/jboss_tomcat/jboss-2.0-FINAL/bin/run.jar
/jboss_tomcat/jboss-2.0-FINAL/bin
/jboss_tomcat/jboss-2.0-FINAL/conf
/jboss_tomcat/jboss-2.0-FINAL/lib/jaas.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/jboss-jaas.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/jdbc2_0-stdext.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/jmxri.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/xml.jar
/jboss_tomcat/tomcat-3.2-b7/lib/servlet.jar
/jboss_tomcat/tomcat-3.2-b7/lib/jaxp.jar
/jboss_tomcat/tomcat-3.2-b7/lib/webserver.jar
/jboss_tomcat/tomcat-3.2-b7/lib/parser.jar
/jboss_tomcat/tomcat-3.2-b7/lib/jasper.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/activation.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/awt.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/dynaserver.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/ejb.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/ejxeditor.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/ejxejb.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/ejxjaws.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/ejxjboss.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/hsql.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/idb.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/jboss.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/jetty-service.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/jms.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/jmxtools.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/jndi.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/jnpserver.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/jpl-util-0_5b.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/jta-spec1_0_1.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/mail.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/spydermq.jar
/jboss_tomcat/jboss-2.0-FINAL/lib/ext/tomcat-service.jar
/jboss_tomcat/jboss-2.0-FINAL/db
/jboss_tomcat/jboss-2.0-FINAL/log
/jboss_tomcat/jboss-2.0-FINAL/conf/tomcat
</programlisting>
<para>
Also the source dir for jboss sources should be set to:
/jboss_tomcat/jboss-2.0-FINAL/src
</para></listitem>
<listitem><para>Add JBoss Server Library to your project. </para></listitem>
<listitem><para>Rebuild all. </para></listitem>
<listitem><para>Deploy your application.
Copy your jar to the jboss/deploy dir </para></listitem>
</orderedlist>
<para>
If all is well, you should be able to set break points etc and single step your
code. </para>
<para>
Notes
Do NOT include the Sun J2EE SDK jars in your project. </para>
</section>
</section>
1.1 manual/src/docs/howtojca.xml
Index: howtojca.xml
===================================================================
<section><title>JBossCX Configuration</title>
<para>
Author:
<author><firstname>Toby</firstname><surname>Allsop</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section><title>Introduction</title>
<para>
This section describes the configuration changes necessary in order to use
a resource adapter conforming to
the J2EE Connector Architecture (JCA) in your application. </para>
<para>
The JCA specifies how J2EE application components can access resources
other than those explicitly
specified in the J2EE 1.2 specification. It will be part of the J2EE 1.3
specification. You can read more about
the JCA at its <ulink
url="http://java.sun.com/j2ee/connector"><citetitle>official home
page</citetitle></ulink></para>
<para>
JBossCX is the name of the JBoss module that provides RAR deployment and
connects a resource adapter to
a connection manager to create a connection factory accessible by
application components through JNDI. </para>
</section>
<section><title>Contents</title>
<itemizedlist>
<listitem><para><link
linkend="jca1">Terminology</link></para></listitem>
<listitem><para><link linkend="jca2">JBoss
Configuration</link></para></listitem>
<listitem><para><link linkend="jca3">Example - Black Box
Example Adapter from Sun</link></para></listitem>
<listitem><para><link linkend="jca4">Implementation
Status</link></para></listitem>
</itemizedlist>
</section>
<section id="jca1"><title>Terminology</title>
<table><title>Terminology</title>
<tgroup cols="2">
<thead>
<row>
<entry>Concept</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>Resource</entry>
<entry>an external system that provides some service to application
components. Examples include JDBC
databases and mainframe systems</entry>
</row>
<row>
<entry>Resource adapter Connector</entry>
<entry>an application component that implements access to a resource</entry>
</row>
<row>
<entry>Resource instance</entry>
<entry>a particular configuration of a resource, e.g. an Oracle database
running on machine "foo" at port
"1234"</entry>
</row>
<row>
<entry>Connection factory</entry>
<entry>an object, available through JNDI, that provides access to connections
to a particular resource
instance</entry>
</row>
<row>
<entry>Connection manager</entry>
<entry>an object that implements the javax.resource.spi.ConnectionManager
interface - provides connection
pooling, transaction association, security and other "quality of
services"</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section id="jca2"><title>JBoss Configuration</title>
<para>
There are two steps that must be performed to provide access to a
connection factory in JBoss: </para>
<orderedlist>
<listitem><para>Configure a connection factory in jboss.jcml
</para></listitem>
<listitem><para>Deploy the resource adapter </para></listitem>
</orderedlist>
<section><title>Connection Factory Configuration</title>
<para>
Connection factories are created by the ConnectionFactoryLoader MBean, so
an <![CDATA[<mbean> ]]>section must be
added to jboss.jcml for each connection factory that is required. The
format for this entry is as follows.</para>
<programlisting><![CDATA[
<mbean code="org.jboss.resource.ConnectionFactoryLoader"
name="JCA:service=ConnectionFactoryLoader,name=name">
<!-- General attributes -->
<attribute name="name">value</attribute>
<!-- Security attributes -->
<attribute name="name">value</attribute>
</mbean>
]]></programlisting>
<para>General Attributes</para>
<table><title>General Attributes</title>
<tgroup cols="2">
<thead>
<row>
<entry>Name</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>FactoryName</entry>
<entry>The name of the connection factory. This is the name under which the
connection factory will be bound in
JNDI</entry>
</row>
<row>
<entry>RARDeployerName</entry>
<entry>The name of the MBean that will deploy the resource adapter that this
connection factory relates to</entry>
</row>
<row>
<entry>ResourceAdapterName</entry>
<entry>The name of the resource adapter for which this connection factory will
create connections. This is the name
given in the resource adapter's
<![CDATA[ <display-name>]]> deployment
descriptor element</entry>
</row>
<row>
<entry>Properties</entry>
<entry>The properties to set on the resource adapter to configure it to
connect to a
particular resource instance. This is
in java.util.Properties.load format
(essentially one property per line,
name=value)</entry>
</row>
<row>
<entry>ConnectionManagerFactoryName</entry>
<entry>The name of the connection manager factory to use. This is the name
given
in a previously defined
ConnectionManagerFactoryLoader MBean.
Currently there are two choices:
MinervaSharedLocalCMFactory and
MinervaXACMFactory. The former should
be used for resource adapters that
support local transactions and the
latter for those that support XA
transactions.</entry>
</row>
<row>
<entry>ConnectionManagerProperties</entry>
<entry>The properties (in java.util.Properties.load format) to set on the
connection manager for this connection
factory. These properties control
things such as connection pooling
parameters. The example connection
factory in jboss.jcml shows the
possible properties for the Minerva
connection managers</entry>
</row>
</tbody>
</tgroup>
</table>
<!-- <simplelist type="horiz" columns="2">
<member>NAME</member>
<member>DESCRIPTION</member>
<member>FactoryName</member>
<member>The name of the connection factory. This is the name under which the
connection factory will be bound in
JNDI</member>
<member>RARDeployerName</member>
<member>The name of the MBean that will deploy the resource adapter that this
connection factory relates to.</member>
<member>ResourceAdapterName</member>
<member>The name of the resource adapter for which this connection factory
will
create connections. This is the name
given in the resource adapter's
<![CDATA[ <display-name>]]> deployment
descriptor element</member>
<member>Properties</member>
<member>The properties to set on the resource adapter to configure it to
connect to a
particular resource instance. This is
in java.util.Properties.load format
(essentially one property per line,
name=value)</member>
<member>ConnectionManagerFactoryName</member>
<member>The name of the connection manager factory to use. This is the
name given
in a previously defined
ConnectionManagerFactoryLoader MBean.
Currently there are two choices:
MinervaSharedLocalCMFactory and
MinervaXACMFactory. The former should
be used for resource adapters that
support local transactions and the
latter for those that support XA
transactions.</member>
<member>ConnectionManagerProperties</member>
<member>The properties (in java.util.Properties.load format) to set on the
connection manager for this connection
factory. These properties control
things such as connection pooling
parameters. The example connection
factory in jboss.jcml shows the
possible properties for the Minerva
connection managers.</member>
</simplelist> -->
<para>Security Attributes</para>
<para>TBD - no interesting options yet</para>
</section>
<section><title>Deploying the Resource Adapter</title>
<para>
Currently the J2EE deployer does not recognise resource adapters, so it is
not possible to deploy them with the
auto deployer or as part of an EAR. This functionality will be added at a
later date.</para>
<para>
To deploy a resource adapter, and thus activate any connection factories
configured for it, invoke the
deploy(String) operation on the RARDeployer MBean, passing it a URL
pointing to the RAR file containing the
resource adapter. The RAR deployer can also deploy directories that are
structured like a RAR file.</para>
<para>
The easiest way to invoke operations on MBeans is using the HTML adapter
that is, by default, accessible on
port 8082, i.e. point a browser at http://localhost:8082 if running the
browser on the machine running JBoss.
Then find the RARDeployer MBean and it should be self explanatory from
there. </para>
</section>
</section>
<section id="jca3"><title>Example - Black Box Example Adapter from Sun</title>
<para>
For this example you will need Sun's example resource adapter, available
here. The source code for this
resource adapter is also available - this is useful if writing your own
adapter. </para>
<para>
This resource adapter accesses a JDBC 2.0 compliant database. The
advantage of this is that you don't need
any weird or wacky resource to access and that you can compare the
behaviour with a straight JDBC
connection pool. </para>
<para>
In order to make a connection factory from this resource adapter available
to application components, we need
to add the ConnectionFactoryLoader MBean that will create the connection
factory from the resource adapter
when it is deployed. We will create a connection factory called BlackBoxDS
that will appear in JNDI at
java:/BlackBoxDS. Below is the MBean definition that we will use (this is
taken from the default jboss.jcml.</para>
<programlisting><![CDATA[
<!-- Example connection factory for the example "Black Box" resource
adapter. This points at the same database as DefaultDS. -->
<mbean code="org.jboss.resource.ConnectionFactoryLoader"
name="JCA:service=ConnectionFactoryLoader,name=BlackBoxDS">
<attribute name="FactoryName">BlackBoxDS</attribute>
<attribute name="RARDeployerName">JCA:service=RARDeployer</attribute>
<attribute name="ResourceAdapterName">Black Box LocalTx
Adapter</attribute>
<attribute name="Properties">
ConnectionURL=jdbc:HypersonicSQL:hsql://localhost:1476
</attribute>
<attribute
name="ConnectionManagerFactoryName">MinervaSharedLocalCMFactory</attribute>
<!-- See the documentation for the specific connection manager
implementation you are using for the properties you can set -->
<attribute name="ConnectionManagerProperties">
# Pool type - uncomment to force, otherwise it is the default
#PoolConfiguration=per-factory
# Connection pooling properties - see
# org.opentools.minerva.pool.PoolParameters
MinSize=0
MaxSize=10
Blocking=true
GCEnabled=false
IdleTimeoutEnabled=false
InvalidateOnError=false
TrackLastUsed=false
GCIntervalMillis=120000
GCMinIdleMillis=1200000
IdleTimeoutMillis=1800000
MaxIdleTimeoutPercent=1.0
</attribute>
<!-- Principal mapping configuration -->
<attribute name="PrincipalMappingClass"
>org.jboss.resource.security.ManyToOnePrincipalMapping</attribute>
<attribute name="PrincipalMappingProperties">
userName=sa
password=
</attribute>
</mbean>
]]></programlisting>
<para>
Note that the connection manager we have chosen is the Minerva local
transaction connection manager. It is
important to choose the connection manager that matches the capabilities
of the resource adapter. This choice
should be automated in the future. </para>
<para>
Once jboss.jcml is set up with the desired connection factory loaders,
start JBoss and bring up the HTML JMX
connector which lives on port 8082 by default. If your browser is running
on the same box as JBoss then you
can just go to http://localhost:8082. Then find the RARDeployer MBean and
invoke the deploy operation,
passing it the URL to the resource adapter you want to deploy. In this
case it is the path to blackbox-tx.rar
which you should save somewhere local. </para>
<para>
Assuming that the deployment was successful, you should now have a
connection factory bound in JNDI at
java:/BlackBoxDS that you can use just like a normal JDBC DataSource.
</para>
</section>
<section id="jca4"><title>Implementation Status</title>
<para>
Note that this section is likely to lag the latest developments in CVS.
When a stable release including JBossCX
is made then this section should reflect the status of the released
implementation. </para>
<section><title>Unimplemented Features</title>
<itemizedlist>
<listitem><para>Automatic connection manager selection based on
resource adapter capabilities. </para></listitem>
<listitem><para>Mapping to more than one resource principal per
connection factory.</para></listitem>
</itemizedlist>
</section>
<section><title>Limitations</title>
<para>
Transaction association doesn't work properly unless the
transaction is started before the connection
is obtained. </para>
</section>
</section>
</section>
1.1 manual/src/docs/howtojmx.xml
Index: howtojmx.xml
===================================================================
<section>
<title>JMX Connector Description and HowTo</title>
<para>Author:
<author><firstname>Andreas</firstname><surname>Shaefer</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section><title>Introduction</title>
<section><title>JMX Spec from Sun</title>
<para>
Sun release recently the final specification, API and Reference Implemenation
to the
<ulink
url="http://www.javasoft.com/products/JavaManagement/index.html"><citetitle>Java
Management
Extention(JMX)</citetitle></ulink>.
The idea behind this is to provide an API to which the component vendors can
make their components
manageable and the management tools vendor can use this API to manage these
components. </para>
<para>
Therefore the whole JMX is separated into 3 parts:
<orderedlist>
<listitem><para>
Components implement a certain API to offer their management API to
the JMX world. There are 3 ways: through an Interface, through a API
descriptions (Open MBean) and through a Model MBean (but for this
have a look at the spec).
</para></listitem>
<listitem><para>
JMX Agent which contains a MBean Server, certain services like
dynamic download, timers, relations etc. and at least one Connector
or Adaptor.
</para></listitem>
<listitem><para>
Management Tool using a Connector or Adaptor to manage the
components of the JMX Agent the tool is connected to.
</para></listitem>
</orderedlist>
</para>
</section>
<section>
<title>
JMX Implementation in JBoss</title>
<para>
At the moment (8th of September 2000) JBoss uses the final release JMX API for
its services defined in the
jboss.conf file (in there you see that also HTML
Adaptor and the JMX Connector are manageable components). In addition JBoss
use the MBean Server implementation
and the HTML adaptor from the JMX-RI.
The JMX Connector also follows the JMX final spec and API.</para>
<para>
You use JMX first when you start JBoss because the Main class loads the MLET
tags from the jboss.conf file and
hand it over to the MBeanServer which loads the
MBean dynamically (MLET is the tag to dynamically load a MBean by the
MBeanServer). Afterwards it went through
the loaded MBeans and starts all the loaded
MBeans. </para>
<para>
Afterwards you can use JMX either trough the JMX HMTL Adaptor on port 8082 or
through the new JMX Connector. The
JMX HTML Adaptor is provided by the
JMX-RI and the source code is not available (it is part of Sun's JDMK which
you have to buy when you want to get
the source as far as I know). The JMX
Connector is part of the JBoss code and should be considered as first draft
because the Connector is mentioned
within the spec by not further specified.
</para>
<para>
Finally JMX is used within the shutdown hook to terminate all the services
before JBoss is terminated itself
(whatever this means) by going through all available
MBeans and send them the stop signal (call the appropriate method).
</para>
</section>
</section>
<section>
<title>Design of the JMX Connector</title>
<section>
<title>Introduction</title>
<para>
According to the JMX spec the Connector should allow a management tool to work
on a MBeanServer and its MBeans
from another JVM which can be on the same
computer or a remote computer. One particular Connector is bound to its
protocol it supports but a MBeanServer
can offer more than one (a JMX agent has to offer
at least an Adaptor or a Connector) supporting different protocols. Because
the spec does not say much about
Connectors I take the freedom and implemented the
actual Connector within JBoss to lay the base for a remote JBoss management
which is a little bit more
comfortable than the HTML Adaptor.</para>
<para>By the way I will take this opportunity to thanks Rickard �berg for his
support. </para>
</section>
<section>
<title>Goals</title>
<para>These are my goals for a JMX Connector:
<itemizedlist>
<listitem><para>Ease of use</para></listitem>
<listitem><para>From the user perspective the Connector should appear
like a local</para></listitem>
<listitem><para>MBeanServer</para></listitem>
<listitem><para>Unsupported methods throw an exception</para></listitem>
<listitem><para>Supports remote notification handling</para></listitem>
<listitem><para>First draft supports RMI protocol</para></listitem>
</itemizedlist>
</para>
<para>
According to the spec the JMX Connector should offer the client a Proxy for a
remote MBean but then the MBean
proxy must be available at compile time and this
compete with the JMX agent requirements that an JMX agent has to support
dynamic loading of MBeans therefore this
is not supported now. </para>
<section>
<title>Design</title>
<para>
The JMX Connector is separated into 4 parts:
<orderedlist>
<listitem><para>Server-side implementation </para></listitem>
<listitem><para>Client-side implementation </para></listitem>
<listitem><para>Connector Factory to lookup servers and protocols
(optional)</para></listitem>
<listitem><para>Test client </para></listitem>
</orderedlist>
</para>
<section>
<title>Server-side implementation</title>
<para>
The server-side implementation is loaded and started by the MBeanServer which
should become available for remote
management. For this we have the necessary
MBean service classes, the Connector implementation and an Object Handler
class.
The Object Handler class is a serializable class allowing the remote client to
deal with remotely instantiated
classes. This eliminates problems with not serializable
classes and with the unique identification of serialized classes (on a round
trip you get a copy of the original
instance). </para>
<para>
The Object Handler is also used to avoid
troubles with not serializable classes used as a Handback object in the
Notification handling. This class allows
the client to work on the JMX Connector as he
would work on a local MBeanServer.</para>
</section>
<section>
<title> Client-side implementation</title>
<para>
The client-side implementation can either be used directly by instantiating
the RMIClientConnectorImpl or by
using the Connector Factory. The client-side
Connector is more or less a MBeanServer which sends the request over the
supported protocol to the server-side
connector and returns the returned object back to
the caller. There are a few methods which cannot be supported and therefore
throw a unsupported operation
exception. </para>
<para>
To make it clear and also for documentation purpose the client-side connector
implements the JMXConnector
Interface. At the moment I want still keep this
interface even when MBeanServer is now an interface too because which all good
programming techniques it is (at
least at the moment) not possible to make it
100% transparent (but see later under limitations). </para>
</section>
<section>
<title> Connector Factory</title>
<para>
When I started with the JMX Connector I had a management tool in mind like the
network administration tool from
CA or the proposed AppCenter from Inprise.
Therefore I want to make it as easy as possible for the client to connector as
many remote MBeanServers as he/she
wants and which any protocol available. The
client should never have to worry about the protocol or to know which classes
are behind. That's why I created
the Connector Factory which allows the client to
search for all the remote available MBeanServers and their supported
protocols. The user only has to select a
server and then a protocol and the Connector Factory
returns the appropriate instance of the JMXConnector interface. </para>
</section>
<section>
<title> Test Client</title>
<para>
The JMX Connector Test Client is first a test tool that the JMX Connector is
working and second a demonstration
how to use it. The test tool first starts a local
MBeanServer and register the Connector Factory as first and then only MBean.
Now the test client ask the
Connector Factory for all available, remote
MBeanServers and let the user select one, then it asks the Connector Factory
for all available Connectors or more
precise all the supported protocols of the
available Connectors. Now the user can select the protocol and the Test Client
loads and starts the appropriate
Connector (if available) and register it as a new
MBean at the local MBeanServer. Afterwards it asks the Connector for all
available MBeans on the remote server,
displays it wit all the attributes and operations
on this remote MBean. At the end it will try to register to all remote MBeans
a notification listener which will
inform the client about notification send by the MBean.
That's why the test client will still run after finishing. When the user
terminates the Test Client it will
remove all the notification listeners from the remote
MBeanServer and terminate the Test Client. </para>
</section>
</section>
</section>
</section>
<section>
<title>How To use the JMX Connector</title>
<para>
You need the following to use the JMX Connector:
<itemizedlist>
<listitem><para>Connector.jar (from client directory)
</para></listitem>
<listitem><para>jnp-client.jar (from client directory)
</para></listitem>
<listitem><para>jmxri.jar (from lib directory) </para></listitem>
<listitem><para>jndi.properties (from conf directory) which you
probably have to
adjust</para></listitem>
</itemizedlist>
</para>
<section>
<title>How to create a client with the server and protocol</title>
<para>
<orderedlist>
<listitem><para>
Instantiate the RMIClientConnectorImpl.
<programlisting>
JMXConnector lConnector = new RMIClientConnectorImpl("server-name"
); </programlisting>
</para></listitem>
<listitem><para>
Use either instance or its interface JMXConnector or MBeanServer. If you
got back an instance you can now
work on the remote MBeanServer like it would be a local one.
</para></listitem>
<listitem><para>
Look up for the available MBeans, its attributes and operations. You can
now retrieve and set the
attributes or perform an operation on the remote MBean.
</para></listitem>
<listitem><para>
If you register a Notification Listener then stop this instance before
terminating the program otherwise
the remote MBeanServer will throw an exception when this Notification
Listener is called.
lConnector.stop();
</para></listitem>
</orderedlist>
</para>
</section>
<section>
<title>How to create a client without the server and protocol/H3> </title>
<para>
First you have to make sure that the JNDI property:
java.naming.provider.url points to the JNDI server your JMX Connectors
are registered to. At the moment you can only have one JMX Connector
running at the same computer (but serveral can be registered at the same
JNDI server) and you can only have one JNDI server. </para>
<orderedlist>
<listitem><para>
Import the necessary classes
<programlisting>
import com.sun.management.jmx.MBeanServerImpl;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServer;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.RuntimeErrorException;
import javax.management.RuntimeMBeanException;
import javax.management.RuntimeOperationsException;
import javax.naming.InitialContext;
import org.jboss.jmx.interfaces.JMXConnector;
import org.jboss.jmx.client.RMIClientConnectorImpl;
</programlisting>
</para></listitem>
<listitem><para>
Instantiate a local MBeanServer (MBeanServerImpl)
<programlisting>
final MBeanServer lLocalServer = new MBeanServerImpl();
</programlisting>
The local variable is made final because it is needed in the shutdown
hook.
</para></listitem>
<listitem><para>
Load the logger MBean (is needed now because the Connector Factory
is a standard JBoss MBean but maybe I should make it to a normal
MBean to make it leaner).
<programlisting>
lLocalServer.createMBean( "org.jboss.logging.Logger", new
ObjectName( "DefaultDomain :name=Logger" ) ); </programlisting>
</para></listitem>
<listitem><para>
Load and start the ConnectorFactory MBean
<programlisting>
final ObjectInstance lFactoryInstance =
lLocalServer.createMBean(
"org.jboss.jmx.client.ConnectorFactoryService", new
ObjectName( "DefaultDomain:name=ConnectorFactory" )
);</programlisting>
</para></listitem>
<listitem><para>
Look for the list of servers (if a null is passed as parameter this
method returns all the servers at the given JNDI server)
<programlisting>
Collection lServers = (Collection) lLocalServer.invoke(
lFactoryInstance.getObjectName(), "getServers", new
String[] {null}, new String[] {"java.lang.String"}
);</programlisting>
and within a server for the list of protocols (if a null or empty
string is passed then all protocols at
the given JNDI server will be listed)
<programlisting>
Collection lProtocols = (Collection) lLocalServer.invoke(
lFactoryInstance.getObjectName(), "getProtocols", new
String[] {lServer}, new String[] {"java.lang.String"} );
</programlisting>
</para></listitem>
<listitem><para>
Create a connection to the selected Connector
<programlisting>
JMXConnector lConnector = (JMXConnector)lLocalServer.invoke(
lFactoryInstance.getObjectName(),"createConnection", new Object[]
{lServer,lProtocol}, new String[]
{"java.lang.String","java.lang.String");
</programlisting>
</para></listitem>
<listitem><para>
Use the new Connector MBean on the local MBeanServer to get and set the
attributes and perform
operation on the chosen MBeans on the remote MBeanServer.
<programlisting>
Iterator i = pConnector.queryMBeans( null, null).iterator();
while( i.hasNext() ) {
MBeanInfo info = pConnector.getMBeanInfo( ( (ObjectInstance)
i.next()).getObjectName() );
MBeanAttributeInfo[] aInfos = info.getAttributes();
.
.
. MBeanOperationInfo[] oInfos = info.getOperations();
}</programlisting>
</para></listitem>
<listitem><para>
Register a Notification Listener on a remote MBean and wait for
notification events sent from the
remote MBean.
<programlisting>
Iterator i = pConnector.queryMBeans( null,
nullitemizedlist).iterator();
int j = 0;
while( i.hasNext() ) {
ObjectInstance lBean = (ObjectInstance) i.next();
try {
pConnector.addNotificationListener( lBean.getObjectName(),
(NotificationListener) new Listener(),(NotificationFilter)
null,
new NotSerializableHandback(lBean.getObjectName() + "" + j++
)
); ... </programlisting>
But when you terminate the connector you have to remove the connection
by using the Connector
Factory to remove all the Notification Listener from the remote
MBeanServer.
<programlisting>
lLocalServer.invoke( lFactoryInstance.getObjectName(),
"removeConnection", new Object[] {lServer,lProtocol}, new
String[] {"java.lang.String","java.lang.String"}
);</programlisting>
</para></listitem>
</orderedlist>
</section>
</section>
<section><title>ToDo List</title>
<para>This list contains all the stuff to be done to make the JMX Connector
full
fledged:
<itemizedlist>
<listitem><para>Implement the server lookup in the Connector Factory to
work with JNDI</para></listitem>
<listitem><para>Implement the protocol lookup in the Connector Factory
to work with JNDI</para></listitem>
<listitem><para>Test all to make sure that it works from any other JVM
that the JBoss VM </para></listitem>
</itemizedlist>
</para>
<para>
This list contains all the stuff to be done around JMX
<itemizedlist>
<listitem><para>Initiate and start full fledged JMX Agent
project</para></listitem>
<listitem><para>Design and implement Relation Service for the JMX
Agent</para></listitem>
<listitem><para>Design and implement graphic management tool for
JBoss</para></listitem>
</itemizedlist>
</para>
<para>
If anything is wrong or not correct please contact me at
[EMAIL PROTECTED] Also if you want to know more in detail
or have a request for changes in the JMX Connector.
</para>
</section>
</section>
1.1 manual/src/docs/howtormhexamples.xml
Index: howtormhexamples.xml
===================================================================
<section><title>Running the Examples from Enterprise JavaBeans, by Richard
Monson-Haefel (Unix) </title>
<para>Author:
<author><firstname>Sebastien</firstname><surname>Alborini</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<para>
This page describes how to run the examples from Richard Monson-Haefel's book
Enterprise JavaBeans, 2nd Edition
(Chapter 4) in JBoss.</para>
<para>
You can download the examples (zip file) from O'Reilly's site. I will assume you
have unzipped this file and you work in
the chapter4/EJB11 directory.</para>
<para>
These examples need to be slightly modified to run with JBoss. You can download the
modified version from here, but I
recommend you to follow these instructions which tell exactly what has to be
modified.</para>
<itemizedlist>
<listitem><para>Setup your environment.</para>
<para>JBoss libraries will be needed to compile and run the examples, so you
have to set the environment variable
JBOSS_HOME to your JBoss installation. For example:
<itemizedlist>
<listitem><para>export JBOSS_HOME=$HOME/jboss_pr4 if you have the binary
version in your home directory </para></listitem>
<listitem><para>export JBOSS_HOME=$HOME/jboss/dist if you have the CVS
version.</para></listitem>
</itemizedlist>
</para>
</listitem>
<listitem><para>Compile and deploy the beans.</para>
<para>The beans are almost ok for JBoss, the only difference is about the
reference made by TravelAgentBean to
CabinBean: a bean must lookup in the java:comp/env namespace. Edit
com/titan/travelagent/TravelAgentBean.java, and replace
<programlisting>
Object obj = jndiContext.lookup("ejb/CabinHome");</programlisting>
with
<programlisting>
Object obj = jndiContext.lookup("java:comp/env/ejb/CabinHome");
</programlisting>
</para>
<para>
This ejb-reference from TravelAgentBean (in travelagent.jar) to CabinBean (in
cabin.jar) is an external
reference (different ejb-jar file). You must then provide the full jndi name
for CabinBean in a jboss.xml for
TravelAgentBean: create and edit com/titan/travelagent/jboss.xml
<programlisting><![CDATA[
<?xml version="1.0"?>
<jboss>
<enterprise-beans>
<session>
<ejb-name>TravelAgentBean</ejb-name>
<ejb-ref>
<ejb-ref-name>ejb/CabinHome</ejb-ref-name>
<jndi-name>CabinBean</jndi-name>
</ejb-ref>
</session>
</enterprise-beans>
</jboss>
]]></programlisting>
</para>
<para>
You don't jave to change anything in ejb-jar.xml. You can now use the following
script jbossMakeIt.sh to
compile and deploy:
<literallayout>
<command><![CDATA[
#!/bin/sh
# make cabin bean
javac -classpath $JBOSS_HOME/lib/ext/ejb.jar:. \
com/titan/cabin/Cabin*.java
cp com/titan/cabin/ejb-jar.xml META-INF/ejb-jar.xml
jar cvf cabin.jar com/titan/cabin/Cabin*.class META-INF/ejb-jar.xml
# make travelagent bean
javac -classpath $JBOSS_HOME/lib/ext/ejb.jar:. \
com/titan/travelagent/TravelAgent*.java
cp com/titan/travelagent/ejb-jar.xml \
com/titan/travelagent/jboss.xml \
META-INF/
# JBoss needs the Home, Remote and primary key (PK) classes
# of the Cabin in travelagent.jar so that TravelAgent*.class
# can access the Cabin bean
jar cvf travelagent.jar \
com/titan/cabin/CabinHome.class \
com/titan/cabin/Cabin.class \
com/titan/cabin/CabinPK.class \
com/titan/travelagent/TravelAgent*.class \
META-INF/ejb-jar.xml META-INF/jboss.xml
rm -f META-INF/ejb-jar.xml
rm -f META-INF/jboss.xml
# deploy
cp cabin.jar travelagent.jar $JBOSS_HOME/deploy
]]></command></literallayout>
</para></listitem>
<listitem><para>Compile the clients.</para>
<para>
The clients from the examples perform a lookup on the java:comp/env namespace,
which is not
currently supported by JBoss for the clients. You have to make the following
edits: (CabinBean is the jndi
name under which the Cabin Bean is deployed, see the jndi howto)
In com/titan/cabin/Client_1.java replace
<programlisting>
Object obj = jndiContext.lookup("java:comp/env/ejb/CabinHome");</programlisting>
by
<programlisting>
Object obj = jndiContext.lookup("CabinBean");</programlisting>
In com/titan/cabin/Client_2.java replace
<programlisting>
Object obj = jndiContext.lookup("ejb/CabinHome");</programlisting>
by
<programlisting>
Object obj = jndiContext.lookup("CabinBean");</programlisting>
In com/titan/travelagent/Client_1.java replace
<programlisting>
Object obj = jndiContext.lookup("ejb/CabinHome");</programlisting>
by
<programlisting>
Object obj = jndiContext.lookup("CabinBean");</programlisting>
You can now use jBossMakeClients.sh to compile:
<literallayout>
<command>
#!/bin/sh
javac -classpath $JBOSS_HOME/lib/ext/ejb.jar:. \
com/titan/cabin/Client*.java \
com/titan/travelagent/Client*.java
</command>
</literallayout>
</para></listitem>
<listitem><para>Run the clients</para>
<para>
We don't use Sun's RI runclient tool, so RunIt.sh won't work. Instead, we
provide the following script:
jBossRunClient.sh. This file includes all the jBoss libraries needed in the
classpath.
<literallayout>
<command>
#!/bin/sh
CP=$JBOSS_HOME/client/ejb.jar
CP=$CP:$JBOSS_HOME/client/jndi.jar
CP=$CP:$JBOSS_HOME/client/jta-spec1_0_1.jar
CP=$CP:$JBOSS_HOME/client/jboss-client.jar
CP=$CP:$JBOSS_HOME/client/jnp-client.jar
CP=$CP:.
java -cp $CP $1
</command>
</literallayout>
You also have to set the jndi properties to connect to the server. This is done
in the jndi.properties file (this file
must be in the same directory as jBossRunClient.sh)
<programlisting>
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost
java.naming.factory.url.pkgs=org.jboss.naming;
</programlisting>
You can now run the clients. The script take the name of the client as an
argument, try
<literallayout>
<command>
./jBossRunClient.sh com.titan.cabin.Client_1
./jBossRunClient.sh com.titan.cabin.Client_2
./jBossRunClient.sh com.titan.travelagent.Client_1
</command></literallayout>
</para>
<para>
NOTES:
the clients will only run once, since they use the EJBHome.create() method:
at second run, a
DuplicateKeyException will occur.
I recommend you to turn off debug logging for these examples. Edit
$JBOSS_HOME/conf/jboss.conf, in
the ConsoleLogging section, set the first ARG to "Error".
</para>
</listitem>
</itemizedlist>
</section>
1.1 manual/src/docs/howtotimer.xml
Index: howtotimer.xml
===================================================================
<section>
<title>How To us the Timer MBean</title>
<para>Author:
<author><firstname>Andreas</firstname><surname>Shaefer</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section>
<title>Introduction</title>
<para>
As part of the JMX specification each JMX compliant server must provide a
timer service to let the users
beeing notified at a certain time, in a certain interval and/or number of
occurrences.
Therefore you can check for mails, check if some change on target (auto
deployer) or notify the client for a
date.</para>
</section>
<section>
<title>Preparation</title>
<itemizedlist>
<listitem>
<para>
First you have to add the timer service into the jboss.conf therefore that
the timer service is loaded, registered
at the JMX server and the initialized and started (done by JBoss's Main.java
class). This MLET tag looks like
this:
<programlisting><![CDATA[
<MLET CODE = "javax.management.timer.Timer"
NAME="DefaultDomain:service=timer"
ARCHIVE="jmxri.jar" CODEBASE="../../lib"> </MLET>
]]></programlisting>
</para>
</listitem>
<listitem>
<para>
If you are not using JBoss then to the following:
<orderedlist>
<listitem><para>
Create a MBeanServer
<programlisting>
MBeanServer lServer =
MBeanServerFactory.createMBeanServer();
</programlisting>
</para></listitem>
<listitem><para>
Load and register the Timer MBean
<programlisting>
ObjectInstance lTimer =
lServer.createMBean(
"javax.management.timer.Timer", new
ObjectName( "DefaultDomain",
"service", "timer" ) );
</programlisting>
</para></listitem>
<listitem><para>Initialize and start the timer service
<programlisting>
lServer.invoke(
lTimer.getObjectName(), "init", new
Object[] {}, new String[] {} );
lServer.invoke(
lTimer.getObjectName(), "start", new
Object[] {}, new String[] {} );
</programlisting>
</para></listitem></orderedlist>
</para>
</listitem>
<listitem>
<para>Next step is to get the MBeanServer within your object to work with the
timer.</para>
<para>
This is quite simple if your are in a MBean registered to the same
JMX server because
then you get it when you overwrite preRegister() method.
When you are in the same JVM as the JMX server (in JBoss is any
instance running
within JBoss like EJBs or other classes). Then you can obtain the
MBeanServer throug: </para>
<programlisting>
MBeanServer lServer =
MBeanServerFactory.createMBeanServer();</programlisting>
<para>
For the rest it is a little bit more complicated. In a Java client
you can use JBoss RMI
connector which will be released as separat package till mid
December 2000. Then you
connect to a MBeanServer through the JMXConnector interface which is
more or less
the same. </para>
</listitem>
<listitem>
<para>
We are nearly there: now we need the reference to the timer service to work
on it (lServer can be either of
type MBeanServer or JMXConnector): </para>
<programlisting>
Set lBeans = lServer.queryMBeans( new ObjectName(
"DefaultDomain", "service", "timer" ), null ); if(
!lBeans.isEmpty() ) { // Should be the first and
only element ObjectInstance lTimer =
(ObjectInstance) lBeans.iterator().next();
</programlisting>
</listitem>
<listitem>
<para>
Let's go to work with the timer. Because the timer sends a Notification Event
to the listeners we have to
register first: </para>
<programlisting>
lServer.addNotificationListener(
lTimer.getObjectName(), new Listener(), // No
filter null, // No object handback necessary null
);</programlisting>
</listitem>
<listitem>
<para>
The Listener (in this case) is an inner class implementing the
NotificationListener interface: </para>
<programlisting>
public class Listener implements
NotificationListener { public handleNotification(
Notification pNotification, Object pHandback ) {
// Here to whatever you want or call a method //
in the outer class System.out.println( "You got a
Notification: " + pNotification ); } } </programlisting>
</listitem>
<listitem>
<para>
Finally we are ready to rock and roll. We set a timer event for a particular
time and at this time the
Listener.handleNotification() get called.</para>
<programlisting>
Integer lOneMinuteTimer = lServer.invoke(
lTimer.getObjectName(), "addNotification", new
Object[] { "IDoNotKnowWhatTypeIs", "I call you
with this timer once", // No user object null, //
I one minute from now new Date( new
Date().getTime() + Timer.ONE_MINUTE ), }, new
String[] { String.getClass().getName(),
String.getClass().getName(),
Object.getClass().getName(),
Date.getClass.getName() } ); </programlisting>
</listitem>
<listitem>
<para>
A timer notification after an Hour from now repeating every minute for ten
times.</para>
<programlisting>
Integer lOneHourTimer = lServer.invoke(
lTimer.getObjectName(), "addNotification", new
Object[] { "IDoNotKnowWhatTypeIs", "I call you
with this timer once", // No user object null, //
I one minute from now new Date( new
Date().getTime() + Timer.ONE_HOUR ),
Timer.ONE_MINUTE, 10 }, new String[] {
String.getClass().getName(),
String.getClass().getName(),
Object.getClass().getName(),
Date.getClass.getName(), Long.TYPE.getName(),
Long.TYPE.getName() } ); </programlisting>
</listitem>
<listitem>
<para>
If you want to get ride of the second timer then do:</para>
<programlisting>
lServer.invoke( lTimer.getObjectName(), "removeNotification", new
Object[] {
// You could also use the type: "IDoNotKnowWhatTypeIs" lOneHourTimer },
new String[] { // If you remove by type: String.getClass().getName()
Integer.TYPE.getName() } ); </programlisting>
</listitem>
</itemizedlist>
<para>
Now the rest is quite simple. Have a look at the javax.management.Timer class
description and use the
MBeanServer.invoke() method style.</para>
<para>Attention: When you have basic data type in the method signature then
you have to use its wrapper class TYPE variable to get its class instead of
using just "long" etc.</para>
<para>If anything is wrong or not correct please contact me at
[EMAIL PROTECTED] Also if
you want to know more in detail or have a request for further infos.</para>
</section>
</section>
1.1 manual/src/docs/howtotomcat.xml
Index: howtotomcat.xml
===================================================================
<section><title>Running Tomcat with JBoss</title>
<section><title>Goal</title>
<para>
As part of project Game Over, the JBoss organization wants to deliver a complete
J2EE based product to the market. The JBoss organization decided to integrate the
Tomcat
engine stack with a running version of JBoss in a single VM. Now you can serve all
your servlet and JSP needs with 2 simple downloads and a couple of configuration files.
Check out the Tomcat homepage for information related to Tomcat. </para>
<para>
The goal of this page is to explain how to make JBoss automatically start Tomcat,
so that it runs in the same VM.</para>
</section>
<section><title>Benefits</title>
<para>
One benefit of running Tomcat inside the same VM as JBoss is to have an easier to
manage application server. The main goal, however, is greater performance. By
eliminating
unnecessary network calls and keeping all the invocations inside one VM the
performance is significantly enhanced.</para>
<para>
If you have Servlets/JSPs which access some EJBs, you'll get dramatically improved
performance because the calls will be intra-VM (no network access).</para>
<para>
WARNING
THIS IS STILL A BETA VERSION. </para>
</section>
<section><title>Requirements</title>
<para>
JBoss 2.0. BETA-PROD 03
Tomcat Version 3.2b4. You can get the latest release of tomcat from the
jakarta website.</para>
<para>
NOTE: This has been tested with tomcat up to 3.2b6, and should work with the
forthcoming final 3.2 version. However it won't run on tomcat 3.1, and tomcat 3.3 is
not
suppported yet. </para>
</section>
<section><title>How-to setup jboss for tomcat</title>
<para>
<itemizedlist>
<listitem><para>Setup environment variables.In whatever batch or shell script
you use to launch JBoss and Tomcat, add entries for the following environment variables
<table><title>Enviromental variables</title>
<tgroup cols="2">
<thead>
<row>
<entry>Variable</entry>
<entry>Value</entry>
</row>
</thead>
<tbody>
<row>
<entry>TOMCAT_HOME</entry>
<entry>The base directory of Tomcat's binaries. With the binary distribution,
this would be jakarta-tomcat under your installation root</entry>
</row>
<row>
<entry>JAVA_HOME</entry>
<entry>The base directory of your JDK 1.2.2 or 1.3 installation</entry>
</row>
<row>
<entry>CLASSPATH</entry>
<entry>This should not include anything (unless you really know what you're
doing!). Both Tomcat and JBoss have startup scripts that load the necessary
JARs onto the classpath.</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
</listitem>
<listitem><para>Edit jboss.conf. It is located in the conf directory under the
base of your JBoss binary distribution, or the dist/conf directory
if you built from the JBoss source. There are some commented-out lines near
the end of the file that deal with Tomcat:
<programlisting><![CDATA[
<!--
-- Uncomment this to add "Integrated Stack (fast) Tomcat support".
-- This service allows you to integrate the stack of Tomcat and jboss.
-- Invocations are not going through network but pass native
-- pointers resulting in dramatic speed increases.
-- This service allows the J2EE deployer to add and remove Tomcat contexts
dynamically
-- through JMX for you and in effect deploy EARs. Note that tomcat's
-- server.xml file will be partially processed for context support: you can
-- also use JMX to add contexts.
-- Use the J2EE deployer to deploy full EARs on this stack
-- Be sure to set your 'TOMCAT_HOME' environment variable before starting
JBoss.
--
-- The ARG tags are the config file and the port to run tomcat on. Note:
only the url
-- contexts will be parsed, (path and docBase attruibutes only) all other
-- configurations are not yet supported.
--
-- MLET CODE = "org.jboss.tomcat.EmbeddedTomcatService" ARCHIVE="jboss.jar"
CODEBASE="../../lib/ext/">
-- ARG TYPE="java.lang.String" VALUE="full path to tomcat config file">
-- ARG TYPE="int" VALUE=8080>
-- /MLET>
]]></programlisting>
</para>
<para><![CDATA[
You need to uncomment these lines so they read as follows (note you must add
the < signs at the beginning of the
three relevant lines and the file path must always begin with a '/'): ]]>
<programlisting><![CDATA[
<MLET CODE = "org.jboss.tomcat.EmbeddedTomcatService" ARCHIVE="jboss.jar"
CODEBASE="../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="/yyy/server.xml">
<ARG TYPE="int" VALUE=8080>
</MLET>
]]>
</programlisting>
</para>
</listitem>
<listitem><para>Start JBoss. If you start JBoss now by typing run.sh (or run.bat
for Windows) you should see the following Tomcat related output
in your log messages:
<programlisting>
...
[EmbeddedTomcat] Initializing
[EmbeddedTomcat] Initialized
[EmbeddedTomcat] Starting
[EmbeddedTomcat] Testing if Tomcat is present....
[EmbeddedTomcat] OK
[EmbeddedTomcat] ContextManager: Adding context Ctx( )
[EmbeddedTomcat] path="" :jsp: init
[EmbeddedTomcat] PoolTcpConnector: Starting HttpConnectionHandler on 8080
[EmbeddedTomcat] Started
...
</programlisting>
</para>
</listitem>
</itemizedlist>
</para>
<para>
That's it !! You just have to launch JBoss now and it will start Tomcat and you
will have an EJB/JSPs/Servlets server running in one VM... </para>
</section>
<section><title>How-to build web applications for jboss and tomcat</title>
<para>
In order to benefit from the classloader integration, you have to deploy your
application in an ear file as recommended by the J2EE specification.</para>
<para>
Tomcat's server.xml file will not be processed!</para>
<para>
The reason is that we want to share the classloader for your application between
tomcat and jboss. Since this classloader must be initialized at
deployment time, your EJBs and your servlets/JSPs must be bundled together for
jboss to know who talks to whom! </para>
<para>
In case you don't want to read all the J2EE spec, here is a brief summary of what
you have to do:</para>
<orderedlist>
<listitem><para>Write your beans and package them in an ejb-jar file. You don't
have to do anything special here.
See the manual for details on how to package beans for jboss.</para></listitem>
<listitem><para>Write your servlets/JSPs and package them in a war file.
Assuming you have a bean deployed under the jndi name "myBean",
the calls to this bean from your servlets will look like that: </para>
<programlisting>
MyBeanHome home = (MyBeanHome)new InitialContext().lookup("myBean");
MyBean bean = home.create();
</programlisting>
<para>
Notes:
We don't support lookups in the "java:" namespace from the servlets yet,
but work is in progress.
Since jboss takes care of the classloader stuff, you don't have to
include much in the WEB-INF/lib directory: you don't any of your beans interfaces, and
you
don't need the usual jboss-client.jar, jnp-client.jar... </para>
</listitem>
<listitem><para>Package your application in an ear file. An ear file is a jar
archive which contains:</para>
<itemizedlist>
<listitem><para>Your jar files</para></listitem>
<listitem><para>Your war files</para></listitem>
<listitem><para>A deployment descriptor for your application. This file
must be named "application.xml", and must be located in the META-INF
directory in the ear archive. This file tells jboss which modules are
EJBs, which ones are web modules, and the context paths for the web-modules.
Here is a sample application.xml file:
<programlisting><![CDATA[
<?xml version="1.0" encoding="ISO-8859-1"?>
<application>
<display-name>My application</display-name>
<module>
<web>
<web-uri>webmodule.war</web-uri>
<context-root>/servlets</context-root>
</web>
</module>
<module>
<ejb>beans.jar</ejb>
</module>
</application>
]]></programlisting>
</para></listitem>
</itemizedlist>
<para>
See also the DTD for application.xml on Javasoft's website. </para>
</listitem>
<listitem><para>Deploy your ear file. Surf to http://yourhost:8082, and find the
J2eeDeployer service. Give it the URL of your ear file
(don't forget the protocol, be it http: or file:), and click on the deploy
button.</para></listitem>
<listitem><para>That's it! The server console should show your application being
deployed on tomcat and jboss, and your web module should be available on
http://yourhost:8080/servlets (assuming the context-root was
"/servlets").</para></listitem>
</orderedlist>
<para>
For a full example including a servlet and an EJB, see the contrib module </para>
</section>
</section>
1.1 manual/src/docs/jdbc-database.xml
Index: jdbc-database.xml
===================================================================
<chapter><title>JDBC/Database configuration</title>
<para>Author:
<author><firstname>Aaron</firstname><surname>Mulder</surname></author>
<email>[EMAIL PROTECTED]</email>
</para>
<section><title>Introduction</title>
<section><title>Data Sources</title>
<para>
One of the most common requirements is to create one or more data sources for your
EJBs. You must create a data source for CMP entity beans, and it is
the recommended way to interact with a database for BMP entity beans and session
beans.</para>
<para>
JBoss data sources provide database connection pooling. This means that when your
application closes a connection, it is not really closed, just returned
to the "ready" state. The next time your application requests a database connection,
it may reuse the same connection. This saves you the overhead of
opening new database connections for every request, and since normal web
applications use connections very often but for a very short period of time,
the savings can be significant. However, there are some new issues raised such as
the fact that a database connection that is left unused in the pool for a
long period of time may timeout. The JBoss pools have a number of configuration
parameters to address issues like this.</para>
<para>
Supported Databases
JBoss supports any database with a JDBC driver. We recommend pure java drivers (type
3 or type 4), and specifically suggest you do not use the
JDBC-ODBC bridge (type 1).</para>
</section>
<section><title>Mappings Available for CMP Entities</title>
<para>
If we have not worked with a database product before we may need to work with you to
generate a type mapping if you plan to use container managed
persistence. The mappings we have tested extensively include PostgreSQL, InstantDB,
Hypersonic SQL, Oracle 7, Oracle 8, Sybase, DB2, and
InterBase. Additional contributed mappings include PointBase, SOLID, mySQL, MS SQL
Server, and DB2/400. If you would like to support CMP for
another DBMS, or have a working mapping to share, please contact the JBoss Mailing
List.
</para>
</section>
<section><title>Installing JDBC Drivers</title>
<para>
To install a JDBC driver, it must be distributed as one or more ZIP or JAR files.
You should copy those files to the lib/ext directory under your JBoss
installation directory. In addition, you need to change one line in the file
jboss.properties located in the conf directory. Find the property named
jdbc.drivers, and add your product's driver class name to the list of drivers. The
drivers in the list should be separated by commas. Here's an
example line, listing drivers for Oracle and Sybase:
<programlisting>jdbc.drivers=oracle.jdbc.driver.OracleDriver,com.sybase.jdbc2.jdbc.SybDriver</programlisting>
</para>
<para>
The next time you start JBoss, you should see output like the following listing each
driver that was loaded. If instead you see an error for the driver (also
shown below), make sure that you installed the required ZIPs and/or JARs to the
lib/ext directory.
<computeroutput>
[JDBC] Loaded JDBC-driver:oracle.jdbc.driver.OracleDriver
[JDBC] Could not load driver:com.sybase.jdbc2.jdbc.SybDriver
</computeroutput>
</para>
</section>
</section>
<section><title>Creating DB Connection Pools</title>
<para>
Once your JDBC driver is installed, you can add one or more connection pools that
use it. Any number of EJBs may share one connection pool, but you
may want to create multiple pools for a number of reasons. For example, you may want
a dedicated pool for an application that requires very high reponse
time, while other applications share a pool of limited size.</para>
<para>
To add a pool, you need to add sections to jboss.conf and jboss.jcml, both of which
can be found in the conf directory.</para>
<section><title>The JDBC 2.0 Optional Package</title>
<para>
Before we configure the pool, we need to take a brief detour into specifications.
The JDBC API distributed with JDKs 1.1 through 1.3 defines a transaction
for every connection. It is not possible to have more than one connection in a
transaction, or to use a single connection for more than one transaction at a
time.</para>
<para>
Though perfectly adequate for normal use, this falls short of the functionality
mandated by the J2EE specification for enterprise applications. In the J2EE
environment, beans are allowed to use multiple data source, which may include
messaging services, legacy systems, and other non-database sources.
Further, all work against all data sources can be committed or rolled back together.
This means that a EJBs must be able to use more than one data source
per transaction, and in particular more than one connection per transaction.</para>
<para>
Thus was born the JDBC 2.0 Optional Package (the API formerly known as the JDBC 2.0
Standard Extension). This API defines the javax.sql package,
including interfaces such as DataSource, XADataSource, and XAConnection. Some
drivers support this already, though most do not. And some that do
support it do not do a very good job yet (some Oracle implementations, in
particular, neglect important event notifications).</para>
<para>
You must determine whether your driver supports the JDBC 2.0 Optional Package in
order to configure JBoss appropriately. If it does not, JBoss will
simulate it so that your EJBs will operate appropriately, but there are two
important restrictions:
<orderedlist>
<listitem><para>If you request more than one connection from a DataSource in the
context of the same transaction, JBoss will return the same connection every
time. This is so changes made by one bean will be visible to other beans
operating in the same transaction.</para></listitem>
<listitem><para>The connections cannot determine ahead of time whether it is
possible for them to commit, so they cannot participate fully in the two-phase
commit protocol used to commit multiple data sources. This means that if
there's a problem with one of the data sources, some may commit and
others may rollback. This is why we want all DB vendors to fully support the
JDBC 2.0 Optional Package.</para></listitem>
</orderedlist>
</para>
</section>
<section><title>Configuration File Changes</title>
<para>
First, you need to add a section to jboss.conf for each pool. This declares a JMX
service (an MBean) for the the pool. There's a sample below. It
does not matter where in the file you add these lines; the startup order is not
dependent on the order of services in the file. You should make the following
changes to customize your pool:
<itemizedlist>
<listitem><para>In the first line, you should replace "vendor.jar" with the
name of the ZIPs or JARs you added to the lib/ext directory when you configured
the driver</para></listitem>
<listitem><para>
Enter the name you want to use for this pool instead of "PoolName" for the
first argument.</para></listitem>
<listitem><para>If your driver supports the JDBC 2.0 Optional Package, you
should use the class name of the vendor's XADataSource implementation for the
second argument. Otherwise, use the JBoss class name shown.</para></listitem>
</itemizedlist>
<programlisting><![CDATA[
<MLET CODE="org.jboss.jdbc.XADataSourceLoader" ARCHIVE="jboss.jar,vendor.jar"
CODEBASE="../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="PoolName">
<ARG TYPE="java.lang.String" VALUE="org.jboss.minerva.xa.XADataSourceImpl">
</MLET>
]]></programlisting>
</para>
<para>
Second, you must add a section to jboss.jcml for each pool. This declares all the
parameters for the pool, such as the size, username and password
to use, etc. The parameters will be covered in detail next. The block you need to
add is shown below. You only need to add lines for the parameters you
want to override - anything you want to leave as the default you can omit. JBoss
will add all those lines in when it runs, so you can see the default values.
The example below is a simple configuration with only the JDBC URL, user name, and
password. The one thing you need to change besides the
parameter names and values is the pool name in the first line:
<programlisting><![CDATA[
<mbean name="DefaultDomain:service=XADataSource,name=PoolName">
<attribute name="URL">jdbc:oracle:thin:@serverhostname:1521:ORCL</attribute>
<attribute name="JDBCUser">scott</attribute>
<attribute name="Password">tiger</attribute>
</mbean>
]]></programlisting>
</para>
<section><title>Connection Pool Parameters</title>
<para>
Here is the list of possible parameters for each pool's entry in jboss.jcml. Again,
after you run
JBoss once with your new pool, it will add entries for all of these to jboss.jcml,
using the default
values for anything you didn't specify.</para>
<table><title>Connection pool parameters</title>
<tgroup cols="3">
<thead>
<row>
<entry>Name</entry>
<entry>Connection pool parameters</entry>
<entry>default</entry>
</row>
</thead>
<tbody>
<row>
<entry>URL</entry>
<entry>The JDBC URL used to connect to the data source</entry>
<entry></entry>
</row>
<row>
<entry>JDBCUser</entry>
<entry>The user name used to connect to the data source.</entry>
<entry></entry>
</row>
<row>
<entry>Password</entry>
<entry>The password used to connect to the data source.</entry>
<entry></entry>
</row>
<row>
<entry>Properties</entry>
<entry>Any properties required to connect to the data source. This should
be expressed in a String of the form
name=value;name=value;name=value....</entry>
<entry></entry>
</row>
<row>
<entry>MinSize</entry>
<entry>The minimum size of the pool. The pool always starts with one
instance, but if shrinking is enabled the pool will never
fall below
this size. It has no effect if shrinking is not
enabled.</entry>
<entry>0</entry>
</row>
<row>
<entry>MaxSize</entry>
<entry>The maximum size of the pool. Once the pool has grown to hold this
number of instances, it will not add any more instances. If
one of the
pooled instances is available when a request comes in, it
will be
returned. If none of the pooled instances are available, the
pool will
either block until an instance is available, or return null
(see the
Blocking parameter). If you set this to zero, the pool size
will be
unlimited.</entry>
<entry>0</entry>
</row>
<row>
<entry>Blocking</entry>
<entry>Controls the behavior of the pool when all the connections are in
use. If set to true, then a client that requests a connection
will wait
until one is available. If set to false, then the pool will
return null
immediately (and the client may retry).
Note: If you set blocking to false, your client must be
prepared to
handle null results!</entry>
<entry>true</entry>
</row>
<row>
<entry>LoggingEnabled</entry>
<entry>Whether the pool should record activity to the JBoss log. This
includes events like connections being checked out and
returned. It
is generally only useful for troubleshooting purposes (to
find a
connection leak, etc.).</entry>
<entry>false</entry>
</row>
<row>
<entry>GCEnabled</entry>
<entry>Whether the pool should check for connections that have not been
returned to the pool after a long period of time. This would
catch
things like a client that disconnects suddenly without closing
database connections gracefully, or queries that take an
unexpectedly long time to run. This is not generally useful
in an EJB
environment, though it may be for stateful session beans that
keep a
DB connection as part of their state. This is in contrast to
the idle
timeout, which closes connection that have been idle in the
pool.</entry>
<entry>false</entry>
</row>
<row>
<entry>GCMinIdleTime</entry>
<entry>If garbage collection is enabled, the amount of time (in milliseconds)
that must pass before a connection in use is garbage
collected -
forcibly returned to the pool.</entry>
<entry>1200000 (20m)</entry>
</row>
<row>
<entry>GCInterval</entry>
<entry>How often garbage collection and shrinking should run (in
milliseconds), if they are enabled.</entry>
<entry>120000 (2m)</entry>
</row>
<row>
<entry>IdleTimeoutEnabled</entry>
<entry>Whether the pool should close idle connections. This prevents the
pool from keeping a large number of connections open
indefinitely
after a spike in activity. Any connection that has been
unused in the
pool for longer than this amount of time will be closed. If
you do not
want the pool to shrink so rapidly, you can set the
MaxIdleTimeoutPercent and then some connections will be
recreated to replace the closed ones. This is in contrast to
garbage
collection, which returns connections to the pool that have
been
checked out of the pool but not returned for a long period of
time.</entry>
<entry>false</entry>
</row>
<row>
<entry>MaxIdleTimeoutPercent</entry>
<entry>Sets the idle timeout percent as a fraction between 0 and 1. If a
number of connections are determined to be idle, they will
all be
closed and removed from the pool. However, if the ratio of
objects
released to objects in the pool is greater than this
fraction, some
new objects will be created to replace the closed objects.
This
prevents the pool size from decreasing too rapidly. Set to 0
to
decrease the pool size by a maximum of 1 object per test, or
1 to
never replace objects that have exceeded the idle timeout.
The pool
will always replace enough closed connections to stay at the
minimum size.</entry>
<entry>1.0</entry>
</row>
<row>
<entry>IdleTimeout</entry>
<entry>Set the idle timeout for unused connections. If a connection has
been unused in the pool for this amount of time, it will be
released
the next time garbage collection and shrinking are run (see
GCInterval).</entry>
<entry>1800000 (30m)</entry>
</row>
<row>
<entry>TimestampUsed</entry>
<entry>Sets whether object clients can update the last used time. If so, the
last used time will be updated for significant actions
(executing a
query, navigating on a ResultSet, etc.). If not, the last
used time will
only be updated when the object is given to a client and
returned to
the pool. This time is important if shrinking or garbage
collection are
enabled (particularly the latter).</entry>
<entry>false</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
</section>
<section><title>Connection Pool Configuration Examples and Driver Notes</title>
<para>
Here are some sample database pool configuration file exerpts for a variety of
database products. Note that your configuration may differ slightly if you're
using a different version, different JDBC driver, etc. The parameters you are most
likely to need to change are in bold.</para>
<itemizedlist>
<listitem><para>Oracle 8i with native JDBC 2 Optional Package
XADataSource</para>
<itemizedlist>
<listitem><literallayout>Driver Notes
Extreme Float or Double values will cause SQLExceptions
The Oracle XADataSource requires the Oracle Xid implementation. Other
vendor's XADataSource implementation may or may
not be able to interoperate.</literallayout></listitem>
<listitem><para>lib/ext: classes12.zip</para></listitem>
<listitem><para>jboss.properties</para>
<programlisting>
jboss.xa.xidclass=oracle.jdbc.xa.OracleXid
</programlisting>
</listitem>
<listitem><para>jboss.conf</para>
<programlisting><![CDATA[
<MLET CODE="org.jboss.jdbc.XADataSourceLoader" ARCHIVE="jboss.jar"
CODEBASE="../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="OracleDB">
<ARG TYPE="java.lang.String"
VALUE="oracle.jdbc.xa.client.OracleXADataSource">
</MLET>
]]></programlisting>
</listitem>
<listitem><para>jboss.jcml</para>
<programlisting><![CDATA[
<mbean name="DefaultDomain:service=XADataSource,name=OracleDB">
<attribute
name="URL">jdbc:oracle:thin:@host.domain.com:1521:instance</attribute>
<attribute name="JDBCUser">scott</attribute>
<attribute name="Password">tiger</attribute>
</mbean>
]]></programlisting>
</listitem>
<listitem><para>CMP Type Mapping Names (for jaws.xml): Oracle8
</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>Oracle 7.x,8.x,8i with JDBC 1/2 Wrapper
This configuration is reported to be outdated. It is still here for reference
for older versions.</para>
<itemizedlist>
<listitem><literallayout>Driver Notes
For CMP Entity Beans, Oracle 7 only allows 1 serialized Java Object
per bean (column type LONG RAW). Oracle 8 does not have
this limitation (column type BLOB).
Extreme Float or Double values will cause SQLExceptions
</literallayout></listitem>
<listitem><para>lib/ext: classes12.zip</para></listitem>
<listitem><para>jboss.properties</para>
<programlisting>
jdbc.drivers=oracle.jdbc.driver.OracleDriver
</programlisting>
</listitem>
<listitem><para> jboss.conf </para>
<programlisting><![CDATA[
<MLET CODE="org.jboss.jdbc.XADataSourceLoader" ARCHIVE="jboss.jar"
CODEBASE="../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="OracleDB">
<ARG TYPE="java.lang.String"
VALUE="org.jboss.minerva.xa.XADataSourceImpl">
</MLET>
]]></programlisting>
</listitem>
<listitem><para>jboss.jcml</para>
<programlisting><![CDATA[
<mbean name="DefaultDomain:service=XADataSource,name=OracleDB">
<attribute
name="URL">jdbc:oracle:thin:@host.domain.com:1521:instance</attribute>
<attribute name="JDBCUser">scott</attribute>
<attribute name="Password">tiger</attribute>
</mbean>
]]></programlisting>
</listitem>
<listitem><para>CMP Type Mapping Names (for jaws.xml): Oracle7 and
Oracle8 </para></listitem>
</itemizedlist>
</listitem>
<listitem><para>Hypersonic</para>
<itemizedlist>
<listitem><para>lib/ext: hsql.jar</para></listitem>
<listitem><para>jboss.properties</para>
<programlisting>
jdbc.drivers=org.hsql.jdbcDriver
</programlisting>
</listitem>
<listitem><para> jboss.conf </para>
<programlisting><![CDATA[
<MLET CODE="org.jboss.jdbc.XADataSourceLoader" ARCHIVE="jboss.jar"
CODEBASE="../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="Hypersonic">
<ARG TYPE="java.lang.String"
VALUE="org.jboss.minerva.xa.XADataSourceImpl">
</MLET>
]]></programlisting>
</listitem>
<listitem><para>jboss.jcml</para>
<programlisting><![CDATA[
<mbean name="DefaultDomain:service=XADataSource,name=Hypersonic">
<attribute
name="URL">jdbc:HypersonicSQL:hsql://localhost</attribute>
<attribute name="JDBCUser">sa</attribute>
</mbean>
]]></programlisting>
</listitem>
<listitem><para>CMP Type Mapping Names (for jaws.xml): Hypersonic SQL
</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>DB2 7.1</para>
<itemizedlist>
<listitem><literallayout>Driver Notes
DB2 does not support variables of type "byte", so with CMP entities
they will be serialized. We recommend that you use short or int
variables to avoid this.
For CMP entities, serialized objects are stored as type BLOB(n), where
n is 2000 by default. If you plan to serialize objects larger
than 2000 bytes, you will need to alter the mapping or create the
table manually.
Extreme Float or Double values will cause SQLExceptions and may
corrupt the driver so that further actions fail.
The "net" driver (type 4) is preferred over the "app" driver (type 2),
though only the "app" driver has a native XADataSource
implementation. To use the "net" driver, you must run the "db2jstrt
[port]" tool on your DB server. </literallayout></listitem>
<listitem><para>lib/ext: db2java.zip</para></listitem>
<listitem><para>jboss.properties</para>
<programlisting>
jdbc.drivers=COM.ibm.db2.jdbc.net.DB2Driver
</programlisting>
</listitem>
<listitem><para> jboss.conf </para>
<programlisting><![CDATA[
<MLET CODE="org.jboss.jdbc.XADataSourceLoader" ARCHIVE="jboss.jar"
CODEBASE="../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="DB2">
<ARG TYPE="java.lang.String"
VALUE="org.jboss.minerva.xa.XADataSourceImpl">
</MLET>
]]></programlisting>
</listitem>
<listitem><para>jboss.jcml</para>
<programlisting><![CDATA[
<mbean name="DefaultDomain:service=XADataSource,name=DB2">
<attribute
name="URL">jdbc:db2://host.domain.com:port/database</attribute>
<attribute name="JDBCUser">username</attribute>
<attribute name="Password">password</attribute>
</mbean>
]]></programlisting>
</listitem>
<listitem><para>CMP Type Mapping Names (for jaws.xml):DB2
</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>DB2/400</para>
<itemizedlist>
<listitem><para>lib/ext: jt400.jar </para></listitem>
<listitem><para>jboss.properties</para>
<programlisting>
jdbc.drivers=com.ibm.as400.access.AS400JDBCDriver
</programlisting>
</listitem>
<listitem><para> jboss.conf </para>
<programlisting><![CDATA[
<MLET CODE="org.jboss.jdbc.XADataSourceLoader" ARCHIVE="jboss.jar"
CODEBASE="../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="AS400">
<ARG TYPE="java.lang.String"
VALUE="org.jboss.minerva.xa.XADataSourceImpl">
</MLET>
]]></programlisting>
</listitem>
<listitem><para>jboss.jcml</para>
<programlisting><![CDATA[
<mbean name="DefaultDomain:service=XADataSource,name=AS400">
<attribute name="URL">jdbc:as400://hostname</attribute>
<attribute name="JDBCUser">user</attribute>
<attribute name="Password">pw</attribute>
</mbean>
]]></programlisting>
</listitem>
<listitem><para>CMP Type Mapping Names (for jaws.xml):DB2/400
</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>Sybase Adaptive Server Anywhere 6.x, Adaptive Server
Enterprise 11.9.x, 12.x </para>
<itemizedlist>
<listitem><literallayout>Driver Notes
You must install jConnect 5.2, including the stored procedures which
are distributed with the jConnect package. There are
directions for this in the Installation Instructions chapter of the
jConnect for JDBC Installation Guide.
JAWS cannot create a table automatically for CMP Entity beans (the
server rejects DDL within a transaction)
The jConnect 5.2 JDBC driver does not support variables of type byte
or short, so they will be serialized (column type must be
varbinary or image). We recommend you use int variables instead to
avoid this. </literallayout></listitem>
<listitem><para>lib/ext:jconn2.jar</para></listitem>
<listitem><para>jboss.properties</para>
<programlisting>
jdbc.drivers=com.sybase.jdbc2.jdbc.SybDriver
</programlisting>
</listitem>
<listitem><para> jboss.conf </para>
<programlisting><![CDATA[
<MLET CODE="org.jboss.jdbc.XADataSourceLoader" ARCHIVE="jboss.jar"
CODEBASE="../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="SybaseDB">
<ARG TYPE="java.lang.String"
VALUE="org.jboss.minerva.xa.XADataSourceImpl">
</MLET>
]]></programlisting>
</listitem>
<listitem><para>jboss.jcml</para>
<programlisting><![CDATA[
<mbean name="DefaultDomain:service=XADataSource,name=SybaseDB">
<attribute
name="URL">jdbc:sybase:Tds:host.domain.com:4100/database</attribute>
<attribute name="Password">password</attribute>
<attribute name="JDBCUser">username</attribute>
</mbean>
]]></programlisting>
</listitem>
<listitem><para>CMP Type Mapping Names (for
jaws.xml):Sybase</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>PostgreSQL 7.x </para>
<itemizedlist>
<listitem><literallayout>Driver Notes
Extreme Java "long" values will cause SQLExceptions and may corrupt
the driver so that further actions fail. </literallayout></listitem>
<listitem><para>lib/ext:jdbc7.0-1.2.jar</para></listitem>
<listitem><para>jboss.properties</para>
<programlisting>
jdbc.drivers=org.postgresql.Driver
</programlisting>
</listitem>
<listitem><para> jboss.conf </para>
<programlisting><![CDATA[
<MLET CODE="org.jboss.jdbc.XADataSourceLoader" ARCHIVE="jboss.jar"
CODEBASE="../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="PostgresDB">
<ARG TYPE="java.lang.String"
VALUE="org.jboss.minerva.xa.XADataSourceImpl">
</MLET>
]]></programlisting>
</listitem>
<listitem><para>jboss.jcml</para>
<programlisting><![CDATA[
<mbean name="DefaultDomain:service=XADataSource,name=PostgresDB">
<attribute
name="URL">jdbc:postgresql://host.domain.com/database</attribute>
<attribute name="JDBCUser">postgres</attribute>
<attribute name="Password">foo</attribute>
</mbean>
]]></programlisting>
<para>Note: You must include a user name and password. They can be bogus
if your PostgreSQL installation is configured to "trust" the machine
you're coming from, but you can't leave them out.</para>
</listitem>
<listitem><para>CMP Type Mapping Names (for jaws.xml):PostgreSQL
</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>Interbase 6.x </para>
<itemizedlist>
<listitem><literallayout>Driver Notes
For CMP entity beans, serialized Java Objects are limited to 2000
bytes by default in automatically generated tables. You may
increase this limit by changing the mapping or creating the table
manually.
The interclient JDBC driver seems to have trouble checking whether a
table exists, so until that is resolved you can't have JAWS
create the table anyway. </literallayout></listitem>
<listitem><para>lib/ext:interclient-core.jar</para></listitem>
<listitem><para>jboss.properties</para>
<programlisting>
jdbc.drivers=interbase.interclient.Driver
</programlisting>
</listitem>
<listitem><para> jboss.conf </para>
<programlisting><![CDATA[
<MLET CODE="org.jboss.jdbc.XADataSourceLoader" ARCHIVE="jboss.jar"
CODEBASE="../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="InterBaseDB">
<ARG TYPE="java.lang.String"
VALUE="org.jboss.minerva.xa.XADataSourceImpl">
</MLET>
]]></programlisting>
</listitem>
<listitem><para>jboss.jcml</para>
<programlisting><![CDATA[
<mbean name="DefaultDomain:service=XADataSource,name=InterBaseDB">
<attribute
name="URL">jdbc:interbase://host.domain.com/path/to/database.gdb</attribute>
<attribute name="JDBCUser">sysdba</attribute>
<attribute name="Password">changeme</attribute>
</mbean>
]]></programlisting>
</listitem>
<listitem><para>CMP Type Mapping Names (for
jaws.xml):InterBase</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>mySQL 3.23.24-beta </para>
<itemizedlist>
<listitem><literallayout>Notes:
mySQL does not support transactions before version 3.23.15 (experimental
support). Check the consequences for your configuration.
get mm.mysql-2.0.2-bin.jar from http://www.worldserver.com/mm.mysql/
copy the jar to lib/ext/ </literallayout></listitem>
<listitem><para>jboss.properties</para>
<programlisting>
jdbc.drivers=org.gjt.mm.mysql.Driver
</programlisting>
</listitem>
<listitem><para> jboss.conf </para>
<programlisting><![CDATA[
<MLET CODE="org.jboss.jdbc.XADataSourceLoader" ARCHIVE="jboss.jar"
CODEBASE="../../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="mySQL">
<ARG TYPE="java.lang.String"
VALUE="org.jboss.minerva.xa.XADataSourceImpl">
</MLET>
]]></programlisting>
</listitem>
<listitem><para>jboss.jcml</para>
<programlisting><![CDATA[
At least adjust URL, JDBCUser and Password in the following:
<mbean name="DefaultDomain:service=XADataSource,name=mySQL">
<attribute name="Properties"></attribute>
<attribute name="URL">jdbc:mysql://host/databasename</attribute>
<attribute name="GCMinIdleTime">1200000</attribute>
<attribute name="JDBCUser">EnterDatabaseUserHere</attribute>
<attribute name="MaxSize">10</attribute>
<attribute name="Password">EnterDatabasePasswordHere</attribute>
<attribute name="GCEnabled">false</attribute>
<attribute name="InvalidateOnError">false</attribute>
<attribute name="TimestampUsed">false</attribute>
<attribute name="Blocking">true</attribute>
<attribute name="GCInterval">120000</attribute>
<attribute name="IdleTimeout">1800000</attribute>
<attribute name="IdleTimeoutEnabled">false</attribute>
<attribute name="LoggingEnabled">false</attribute>
<attribute name="MaxIdleTimeoutPercent">1.0</attribute>
<attribute name="MinSize">0</attribute>
</mbean>
]]></programlisting>
</listitem>
<listitem><para>CMP Type Mapping Names (for
jaws.xml):mySQL</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>Microsoft Jet Engine/Access 97</para>
<itemizedlist>
<listitem><literallayout>Driver Notes
This example uses Sun's Jdbc-Odbc bridge. This type 1 JDBC driver is
very convenient if you start working with JBoss-Jet
Engine. It can be slow under heavy loads and should be replaced in
high-load production environments. Also, the driver supports
only JDBC 1, so JDBC 2.0 types like CLOB cannot be used.
The ODBC data source can be created using Control Panel - ODBC Data
Sources.
You can let Access and JBoss use the datasource at the same time. To
do this, start JBoss first, then start Access. Access will
open the datasource in Shared Mode. You can now use Access 97 as
editor, viewer, bulk importer/exporter and query builder
while JBoss can be stopped and started concurrently.
</literallayout></listitem>
<listitem><para>lib/ext:Sun JRE's rt.jar if your not running on a Sun
virtual machine, otherwise none </para> </listitem>
<listitem><para>jboss.properties</para>
<programlisting>
jdbc.drivers=sun.jdbc.odbc.JdbcOdbcDriver
</programlisting>
</listitem>
<listitem><para> jboss.conf </para>
<programlisting><![CDATA[
<MLET CODE="org.jboss.jdbc.XADataSourceLoader" ARCHIVE="jboss.jar"
CODEBASE="../lib/ext/">
<ARG TYPE="java.lang.String" VALUE="JetEngineDB">
<ARG TYPE="java.lang.String"
VALUE="org.jboss.minerva.xa.XADataSourceImpl">
</MLET>
]]></programlisting>
</listitem>
<listitem><para>jboss.jcml</para>
<programlisting><![CDATA[
<mbean name="DefaultDomain:service=XADataSource,name=JetEngineDB">
<attribute name="URL">jdbc:odbc:ODBC datasource name</attribute>
<attribute name="JDBCUser"></attribute>
<attribute name="Password"></attribute>
</mbean>
]]></programlisting>
</listitem>
<listitem><para> Note: a default Jet Engine data source has no user and
password, therefor the JDBCUser and Password attributes are empty. If you need
a user or a password, see the other examples. </para>
<para>You can download this mapping here (if using JdbcOdbc bridge
driver) or here (if using JDBC 2.0 compliant driver). Add the contents to
your jaws.xml in the type-mappings section. </para></listitem>
<listitem><para>CMP Type Mapping Names (for jaws.xml):MS Jet Engine
</para></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</section>
</section>
</chapter>
1.1 manual/src/docs/preface.xml
Index: preface.xml
===================================================================
<preface>
<section><title>Docbook</title>
<para>The approach of writing documentation in HTML was inheretly problem infested.
The content was "polluted" with
HTML presentational tags and such impossible to convert to any other view. Another
big issue was <![CDATA[L&F]]>
consistency. Despite the explicit instruction of which HTML tags to use, authors
couldn't keep up with all complexities
and issue faced when writing HTML documents. Documents were also hard to shuffle
around in a document book thus
leading to a very big maintance costs</para>
<para>After some considerate time spent looking around, we came to the conclusion
that Docbook initiative is the most
reasonable way to go. DocBook is a XML/SGML DTD that lets authors in technical
groups concentrate on the organization
and meaning of the documents they write.</para>
<para>Docbook XML DTD ,which we are using, has accompanying XSL stylesheets that
allow us to define different views of
Docbook-ed XML content i.e., all the presentation issues are solved through XSL
stylesheets. These stylesheets are
very flexible, well maintained, and allow easily customized hooks for specialized
home-brewed styles of views.</para>
<para>Simply put, you have xml tagged content, detached from any fomatting issues,
chunked into logical pieces, which
are then easily (re)arranged, put together, and in the end XSL stylesheet is applied
against it to create any
kind of presentational view.</para>
<para>Docbook DTD's are maintained by independent consortium - <ulink
url="http://www.oasis-open.org"><citetitle>OASIS</citetitle></ulink>.
The principal maintainer of Docbook is <ulink
url="http://www.nwalsh.com"><citetitle>Norman Walsh</citetitle></ulink> , a member of
XSL working group, Sun Microsystems employee.</para>
<para>Although Docbook DTD is very big, 300 + elements, the learning curve is very
steep, and most of the time not more
than 50 elements are used. This <ulink
url="http://www.caldera.de/~eric/crash-course/HTML"><citetitle>article</citetitle></ulink>
is suitable for a first contact with Docbook. A good reference that you might want
to use can be found
<ulink
url="http://www.docbook.org/tdg/html/docbook.html"><citetitle>here</citetitle></ulink>
</para>
</section>
</preface>