User: tobias
Date: 01/02/10 16:04:54
Added: src/docs jboss.xsl jbossapi.xml jbossdocs.xml jbossintro.xml
styles.css
Log:
initial checkin, good HTML and basic pdf support
Revision Changes Path
1.1 manual/src/docs/jboss.xsl
Index: jboss.xsl
===================================================================
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:saxon="http://icl.com/saxon"
xmlns:lxslt="http://xml.apache.org/xslt"
xmlns:xalanredirect="org.apache.xalan.xslt.extensions.Redirect"
xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
version="1.0"
exclude-result-prefixes="doc"
extension-element-prefixes="saxon xalanredirect lxslt">
<xsl:import href="docbook/html/chunk.xsl"/>
<xsl:param name="html.stylesheet">styles.css</xsl:param>
<xsl:param name="toc.section.depth">0</xsl:param>
<xsl:param name="chapter.autolabel" select="0"/>
<xsl:template name="header.navigation">
<xsl:param name="prev" select="/foo"/>
<xsl:param name="next" select="/foo"/>
<xsl:variable name="home" select="/*[1]"/>
<xsl:variable name="up" select="parent::*"/>
<xsl:if test="$suppress.navigation = '0'">
<table border="0"
cellpadding="0" cellspacing="0" height="65">
<tr height="65">
<td rowspan="2">
<img src="images/jboss.gif"
width="432" height="79"/>
</td>
<td rowspan="2"
background="images/gbar.gif" width="100%" align="right"
valign="top">
<a>
<xsl:attribute name="href"><xsl:call-template
name="href.target"><xsl:with-param name="object"
select="$home"/></xsl:call-template></xsl:attribute>
<img
src="images/doc.gif" width="63" height="65" border="0"/>
</a>
<xsl:choose>
<xsl:when
test="count($up)>0">
<a>
<xsl:attribute name="href"><xsl:call-template
name="href.target"><xsl:with-param name="object"
select="$up"/></xsl:call-template></xsl:attribute>
<img
src="images/toc.gif" width="60" height="65" border="0"/>
</a>
</xsl:when>
<xsl:otherwise> </xsl:otherwise>
</xsl:choose>
<xsl:if test="count($prev)>0">
<a>
<xsl:attribute
name="href"><xsl:call-template
name="href.target"><xsl:with-param name="object"
select="$prev"/></xsl:call-template></xsl:attribute>
<img
src="images/prev.gif" width="76" height="65" border="0"/>
</a>
</xsl:if>
<xsl:if test="count($next)>0">
<a>
<xsl:attribute
name="href"><xsl:call-template
name="href.target"><xsl:with-param name="object"
select="$next"/></xsl:call-template></xsl:attribute>
<img
src="images/next.gif" width="60" height="65" border="0"/>
</a>
</xsl:if>
</td>
</tr>
<tr/>
</table>
</xsl:if>
</xsl:template>
<xsl:template name="footer.navigation">
<xsl:param name="prev" select="/foo"/>
<xsl:param name="next" select="/foo"/>
<xsl:variable name="home" select="/*[1]"/>
<xsl:variable name="up" select="parent::*"/>
<xsl:if test="$suppress.navigation = '0'">
<table border="0"
cellpadding="0" cellspacing="0" height="65">
<tr height="65">
<td rowspan="2">
<img src="images/gbar.gif"
width="432" height="79"/>
</td>
<td rowspan="2"
background="images/gbar.gif" width="100%" align="right"
valign="top">
<a>
<xsl:attribute name="href"><xsl:call-template
name="href.target"><xsl:with-param name="object"
select="$home"/></xsl:call-template></xsl:attribute>
<img
src="images/doc.gif" width="63" height="65" border="0"/>
</a>
<xsl:choose>
<xsl:when
test="count($up)>0">
<a>
<xsl:attribute name="href"><xsl:call-template
name="href.target"><xsl:with-param name="object"
select="$up"/></xsl:call-template></xsl:attribute>
<img
src="images/toc.gif" width="60" height="65" border="0"/>
</a>
</xsl:when>
<xsl:otherwise> </xsl:otherwise>
</xsl:choose>
<xsl:if test="count($prev)>0">
<a>
<xsl:attribute
name="href"><xsl:call-template
name="href.target"><xsl:with-param name="object"
select="$prev"/></xsl:call-template></xsl:attribute>
<img
src="images/prev.gif" width="76" height="65" border="0"/>
</a>
</xsl:if>
<xsl:if test="count($next)>0">
<a>
<xsl:attribute
name="href"><xsl:call-template
name="href.target"><xsl:with-param name="object"
select="$next"/></xsl:call-template></xsl:attribute>
<img
src="images/next.gif" width="60" height="65" border="0"/>
</a>
</xsl:if>
</td>
</tr>
<tr/>
</table>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
1.1 manual/src/docs/jbossapi.xml
Index: jbossapi.xml
===================================================================
<chapter>
<title>JBoss API</title>
<section><title>The JBoss API</title>
<para>The JBoss API is available in JavaDoc format <ulink
url="api/index.html">here</ulink>.</para>
</section>
</chapter>
1.1 manual/src/docs/jbossdocs.xml
Index: jbossdocs.xml
===================================================================
<!DOCTYPE book
PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"docbookx/docbookx.dtd" [
<!ENTITY jbossintro.xml SYSTEM "jbossintro.xml">
<!ENTITY jbossapi.xml SYSTEM "jbossapi.xml">
]>
<book>
<bookinfo>
<title>JBoss 2.0 Documentation</title>
<copyright><year>2000</year><year>2001</year>
<holder>JBoss Organization</holder>
</copyright>
</bookinfo>
&jbossintro.xml;
<!--
&cmp.xml;
&customizingjaws.xml;
&advconfig.xml;
&j2eedeployer.xml;
&jbossfinal.xml;
-->
&jbossapi.xml;
</book>
1.1 manual/src/docs/jbossintro.xml
Index: jbossintro.xml
===================================================================
<chapter>
<title>Installing JBoss</title>
<section><title>Introduction</title>
<para>Before installing and running the server, you should check that your JDK
installation is working. (Step-by-step instructions are available.) You will
need the JDK binaries directory in your PATH (this is essential: see below)
not just for the user account which is doing the installation, but also for
the user account that will run the server. If you are running the server as
root, you should check that the JDK binaries are in the PATH even for root
(root and ordinary users normally have different PATH settings). You won't
need to specify a CLASSPATH environment variable if you don't normally have
to.</para>
<para>The next step will be to download, install and test the JBoss server. At
the time of writing the most recent version of JBoss is 2.0. You can get JBoss
from www.jboss.org</para>
<para>It doesn't matter very much where you install JBoss; my preference is to
use /usr/local/jboss. If you don't have root access, or would rather not run
untested software as root, jboss will work perfectly well if installed in a
user directory and run as an ordinary user. I will assume in this tutorial
that you are installing in /usr/local/jboss. If you haven't, change the paths
as appropriate.</para>
<para>JBoss is distributed using Install Anywhere which isn't a natural format
for Linux users. If you're running the X Window System on your Linux machine
and you have Netscape installed with Java enabled, this might work for you.
Otherwise, your best bet right now is to download from CVS or to install from
the Zip file like this:</para>
<literallayout><command>su
mkdir /usr/local/jboss
cd /usr/local/jboss
lynx -source \
http://jboss.org/JBoss2/InstData/Other/install.zip \
> install.zip
mkdir installer
cd installer
unzip ../install.zip
mv c:/jboss2/* ..
cd ..
rm -rf installer
rm -f install.zip
</command></literallayout>
<para>You could try running the server now. Change to the bin directory, and
run the program like this: </para>
<literallayout><command>cd bin
java -jar run.jar
</command>
</literallayout>
<para>In a proper installation, the server should start without any error
messages or exceptions being thrown. It will produce about three pages of
output on startup.</para>
<para>The JBoss distribution is supplied with one test Bean, packaged as
bank.jar. This is supplied in the `deploy' subdirectory, which is where Beans
are placed to deploy them. The effect of this is to deploy the `bank' bean
when the server starts up. This is fine the first time, as it tests that the
SQL server is working, but you can usefully move bank.jar out of the deploy
directory when you are sure that everything's OK, and the server will start up
more quickly.</para>
</section>
<section>
<title>Creating the Bean</title>
<para>
In this step we will write and compile a simple Enterprise JavaBean. You can
download the source code interestEJB.tar.gz for this example; you will need to
unpack it into an empty directory.</para>
<literallayout><command>cd /usr/local/jboss
mkdir examples
cd examples
lynx -source http://jboss.org/interestEJB.tar.gz > interestEJB.tar.gz
gunzip interestEJB.tar.gz
tar xf interestEJB.tar
rm -rf interestEJB.tar
</command></literallayout>
<para>The example -- which is called `Interest' -- is about as simple as an
EJB can get: it is a `stateless session bean'. Its job is to calculate the
amount of compound interest payable on a sum of money borrowed over a
specified term with a specified interest rate. In fact, there is only one
functional line of code in the whole package.</para>
<para>If you want to compile the classes yourself, you'll need to create a
directory hierarchy that reflects the structure of the pacakage. The package
in this example is com.web_tomorrow.interest so you'll need to create the
directory structure:
<literallayout>
com
web_tomorrow
interest
{java source and class files here}
</literallayout>
If you unpack the archive interestEJB.tar.gz it will create this
structure automatically. </para>
</section>
<section><title>EJBs: review</title>
<para> As a reminder, and Enterprise JavaBean has a minimum of three
classes.The remote interface. This is the class that exposes the methods of
the Bean to the outside world. In the example, the remote interface is the
class com.web_tomorrow.interest.Interest The Bean class. This implements the
methods specified by the remote interface. In this example, the Bean class is
com.web_tomorrow.interest.InterestBean The home interface. This specifies how
a new Bean is created, managed and deleted. As a minimum it should specify at
least one create() method. There should be an ejbCreate() method in the Bean
class for each create() method in the home interface. In this example, the
home interface is com.web_tomorrow.InterestHome </para>
<para> Of course, a Bean can include other classes, or even other packages,
but the classes listed above are the minimum. The classes must be packaged
into a JAR archive with a directory structure that reflects the hierarchy of
packages. In the example, the classes are in the package
com.web_tomorrow.interest, so they need to be in the directory </para>
<para>./com/web_tomorrow/interest/</para>
<para>where the `.' represents the current working directory, wherever that
is. You will also need a directory called META-INF to store the deployment
descriptor (always called ejb-jar.xml) and -- optionally -- another XML file
to tell the server about name mappings. With JBoss, this file must be called
jboss.xml.</para>
<para>So before writing the classes, we need a directory structure like this:
<literallayout>
com
web_tomorrow
interest
{java source and class files here}
META-INF
ejb-jar.xml
jboss.xml (optional)
</literallayout>
</para>
<para>If the jar utility is run at the top level of this directory structure,
it will put the files in the right ordering in the archive. We will discuss
the creation of the XML files later.</para>
<para>Of course, in your own work you will create a directory hierarchy that
reflect the package hierarchy you need, rather than `com.web_tomorrow.XXXX'
</para>
</section>
<section>
<title>Coding the classes</title>
<para>We need three classes: the remote interface, the Bean, and the home
interface. All the .java files will go in the subdirectory
./com/web_tomorrow/interest.
The remote interface in this example is very simple.
</para>
<figure><title>Remote interface for the `interest' EJB</title>
<programlisting>
package com.web_tomorrow.interest;
import javax.ejb.EJBObject;
import java.rmi.RemoteException;
/**
This interface defines the `Remote' interface for the `Interest' EJB. Its
single method is the only method exposed to the outside world. The class
InterestBean implements the method.
*/
public interface Interest extends EJBObject
{
/**
Calulates the compound interest on the sum `principle', with interest rate per
period `rate' over `periods' time periods. This method also prints a message to
standard output; this is picked up by the EJB server and logged. In this way we
can demonstrate that the method is actually being executed on the server,
rather than the client.
*/
public double calculateCompoundInterest(double principle,
double rate, double periods) throws RemoteException;
}
</programlisting>
</figure>
<para> The remote interface specifies only one `business method'
calculateCompoundInterest. The home interface is even simpler. </para>
<figure><title>Home interface for the `interest' EJB</title>
<programlisting>
package com.web_tomorrow.interest;
import java.io.Serializable;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
/**
This interface defines the `home' interface for the `Interest' EJB.
*/
public interface InterestHome extends EJBHome {
/**
Creates an instance of the `InterestBean' class on the server, and returns a
remote reference to an Interest interface on the client.
*/
Interest create()
throws RemoteException, CreateException;
}
</programlisting>
</figure>
<para>Finally, here is the Bean class. This is the only one that does any real
work in this simple example.</para>
<figure><title>Bean class for the `interest' EJB</title>
<programlisting>
package com.web_tomorrow.interest;
import java.rmi.RemoteException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
/**
This class contains the implementation for the `calculateCompoundInterest'
method exposed by this Bean. It includes empty method bodies for the methods
prescribe by the SessionBean interface; these don't need to do anything in this
simple example.
*/
public class InterestBean implements SessionBean {
/**
Calulates the compound interest on the sum `principle', with interest rate
per period `rate' over `periods' time periods. This method also prints a
message to standard output; this is picked up by the EJB server and logged.
In this way we can demonstrate that the method is actually being executed on
the server, rather than the client.
*/
public double calculateCompoundInterest(double principle,
double rate, double periods) {
System.out.println ("Someone called `calculateCompoundInterest!'");
return principle * Math.pow(1+rate, periods) - principle;
}
/**
Empty method body
*/
public InterestBean() {}
/**
Empty method body
*/
public void ejbCreate() {}
/**
Empty method body
*/
public void ejbRemove() {}
/**
Empty method body
*/
public void ejbActivate() {}
/**
Empty method body
*/
public void ejbPassivate() {}
/**
Empty method body
*/
public void setSessionContext(SessionContext sc) {}
}
</programlisting>
</figure>
<para>Notice that most of the methods are empty; they have to exist because
they're specified by the SessionBean interface, but they don't need to do
anything in this case.</para>
<para>If you haven't already done so, you should create these .java files in
the directory ./com/web_tomorrow/interest (or unpack the archive with them
in). Then you can compile them using the command
<command>javac
-classpath/usr/local/jboss/lib/ext/ejb.jarcom/web_tomorrow/interest/*.java</command>
</para>
<para>
substituting the correct path to the JBoss class EJB library if you haven't
installed JBoss in /usr/local/jboss. This should create three class files:
InterestBean.class, Interest.class, and InterestHome.class. If you have `make'
on your system, and you have unpacked the archive, you can build all the
classes just be running make in the same directory as the Makefile.
With the classes compiled, it's time to create the deployment
descriptor.</para>
</section>
<section>
<title>The deployment descriptor</title>
<para>Now it's time to create the deployment descriptor. As a reminder, this
file tells the EJB server which classes form the Bean, the home interface and
the remote interface. If there is more than one Bean in the package, it
indicates also how the Beans interact with one another. In this simple
example, there is only one Bean so we won't need to worry about that
part.</para>
<para>Most commercial EJB servers are supplied with graphical tools for
constructing the deployment descriptor. JBoss does have an XML editor, but
it's just as easy to construct the deployment descriptor manually. Here it
is:</para>
<figure><title>Deployment descriptor for the Interest Bean</title>
<literallayout> <![CDATA[
<?xml version="1.0" encoding="Cp1252"?>
<ejb-jar>
<description>JBoss test application</description>
<display-name>Test</display-name>
<enterprise-beans>
<session>
<ejb-name>Interest</ejb-name>
<home>com.web_tomorrow.interest.InterestHome</home>
<remote>com.web_tomorrow.interest.Interest</remote>
<ejb-class>com.web_tomorrow.interest.InterestBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Bean</transaction-type>
</session>
</enterprise-beans>
</ejb-jar>
]]>
</literallayout>
</figure>
<para>The deployment descriptor must be called ejb-jar.xml and it must be in
the directory ./META-INF. A common mistake is to name this directory
`META_INF' (with an underscore, rather than a dash), which won't work.</para>
<para> In principle what we deploy on the server is an application, not a
Bean. In this example our application consists of exactly one Bean, so it
comes to the same thing. In the deployment descriptor, the section
<![CDATA[<ejb-name>Interest</ejb-name>]]> assigns a name to the Bean. jboss
in its
standard configuration will put the bean's home interface under the ejb-name
moniker if you don't specify anything else. In other words, when your
applications want to access the bean through it's home jboss will put it in
JNDI under the ejb-name. </para>
<para>In practice client applications are not forced to use this name.
Typically a developer will not bother with specifying a different name for the
JNDI namespace. However a production installation of a complete application
comprising many beans, will usually use a different name than the one
specified by the developer. Typically it could use `[application name]/[bean
name]', which is what we shall use later.</para>
<para>Although the deployment descriptor format of the ejb-jar.xml file is
common to all EJB servers, and precisely defined in a DTD you can get from
SUN, it doesn't specify some advanced stuff. Specifically it does not know how
to map ejb-name to a deployment JNDI such as the one we just talked about. It
also doesn't know how to map resources. The server may also need to be told
how to manage persistence and state. There is, as yet, no standard way of
specifying these things, and every server implementation does it differently.
</para>
<para>The approach taken by JBoss is it provides a standard behaviour that
works mostly from the ejb-jar.xml file. There is no need for additional
information in most cases. In case of advanced configurations we define the
jboss.xml file that gives all the relevant information to the container, such
as JNDI mapping names, persistence information, database mapping and advanced
container configuration (interceptors and plugins), please refer to the
section on jboss.xml for detailed information of what it can do, we will cover
simple things here. </para>
<para>The standard behaviour of jboss is capable of working from ejb-jar.xml
in 95% of cases and needs jboss.xml only if you need to specify specific
deployment information. </para>
<para>An additional feature of the new metadata is that it works
"differentially". In clear what this means is that if you wish to override the
name of a bean you need to only specify that part of xml tags in the jboss.xml
file.</para>
<para>Using the ejb-name from ejb-jar.xml
for most development purposes, as soon as you provide a ejb-jar.xml with the
beans the container will get the ejb-name as the JNDI name as standard
behaviour. This makes your development life easier.</para>
<para>If you don't provide a jboss.xml file you will find your bean under the
name "Interest".</para>
<para>Overriding ejb-name with a real JNDI name in jboss.xml</para>
<para>If in deployment you would rather use the "myApp/myBean" naming pattern
you need to provide the following text in jboss.xml. </para>
<para>jboss.xml: ()</para>
<figure><title>The JBoss XML descriptor. (Optional, this file is provided by the
Bean deployer)</title>
<literallayout> <![CDATA[
<jboss>
<enterprise-beans>
<session>
<ejb-name>Interest</ejb-name>
<jndi-name>interest/Interest</jndi-name>
</session>
<secure>false</secure>
</enterprise-beans>
</jboss>
]]>
</literallayout>
</figure>
<para>All this file says is that the Bean called Interest is assigned the JNDI
name of interest/Interest.</para>
<para>The indentation is just there for formatting and readability, it is non
important.</para>
<para>So now we've got the deployment descriptor ejb-jar.xml. Again jboss will
happily run just from that file and bind the object under "Interest" as
standard JNDI name. We also have the optional jboss.xml to provide another
name "interest/Interest" to overwrite the standard behaviour with JNDI. We
also have the classes. It's time to package them together.</para>
</section>
<section>
<title>Packaging and deploying the bean</title>
<para>Creation of the Bean package involves building a JAR archive containing
the classes and the XML files. For the example Bean we have been discussing,
this is straightforward; at the top of the directory hierarchy run jar like
this:</para>
<literallayout><command>
jar cvf interest.jar com/web_tomorrow/interest/Interest.class \
com/web_tomorrow/interest/InterestHome.class \
com/web_tomorrow/interest/InterestBean.class \
META-INF
</command></literallayout>
<para>If you have `make' on your system, and you have unpacked the source code
arhive, you can get the same effect simply by executing `make package'. I
strongly recommend using Makefiles or shell scripts to do these operations
because in practice you will be repeating them many times during development
jar builds an archive containing the three classes, and the XML files in the
META-INF directory. If you list the contents of the archive you should see
something like this:</para>
<literallayout><computeroutput>
0 06-16-00 11:34 META-INF/
72 06-16-00 11:35 META-INF/MANIFEST.MF
248 06-16-00 10:12 com/web_tomorrow/interest/Interest.class
300 06-16-00 10:12 com/web_tomorrow/interest/InterestHome.class
877 06-16-00 10:12 com/web_tomorrow/interest/InterestBean.class
549 06-15-00 18:15 META-INF/ejb-jar.xml
3597 06-15-00 17:20 META-INF/jboss.xml
</computeroutput>
</literallayout>
<para>Note that the directory structure must be exactly like this, or it won't
work. Again a common mistake is to do a META_INF (underscore) instead of
META-INF, be careful with this one</para>
<para>To deploy the Bean on the server, all that's necessary is to copy the
.jar file to the `deploy' directory on the server, e.g.,
<command>cp interest.jar /usr/local/jboss/deploy </command></para>
<para>You can do this as often as you like; the server will detect that the
file has changed and automatically re-deploy it. During deployment you should
see the following messages from the server: </para>
<literallayout><computeroutput>
[Auto deploy] Auto deploy of file:/usr/local/jboss/deploy/interest.jar
[Container factory] Deploying:file:/usr/local/jboss/deploy/interest.jar
[Container factory] Deploying Interest
[Container factory] Started: Interest
[Container factory] Bound Interest to interest/Interest
[Container factory] Deployed application: file:/usr/local/jboss/deploy/interest.jar
</computeroutput></literallayout>
<para>If you see a message like this: </para>
<literallayout><computeroutput>
[Container factory] Deploying:file:/usr/local/jboss/deploy/interest.jar
[Container factory] Deployed application file:/usr/local/jboss/deploy/interest.jar
</computeroutput></literallayout>
<para>then no Beans have been deployed -- the server always reports the Beans
that it detects. This usually means that the deployment descriptor ejb-jar.xml
is badly structured, or missing, or in the wrong directory. Note that the
server doesn't need to have the CLASSPATH set with your classes it is done
automatically from the deploy directory.</para>
<para>If everything has gone according to plan, you should now have a Bean
deployed on the server. We will now create a simple test client that runs one
of its methods, just to prove that it's working.</para>
</section>
<section>
<title>Coding the test client</title>
<para>An EJB on its own is no use; we will need at least a simple client to
use its services. A user of EJBs may be another EJB, and ordinary JavaBean, a
JSP page, an applet, or a stand-alone application. In this example, for
simplicity, we will code a simple application. This application will create an
object of class Interest, and execute its one method.</para>
<para>Upon "deployment" of the bean as we have seen in the previous step, the
server has generated all the stubs and skeletons needed for the distributed
calls. What we are going to cover here is the way you lookup a reference in
JNDI from a client and invoke it. It is pretty straightforward.</para>
<para>Here is the test client:</para>
<figure><title>Test client</title>
<programlisting>
import javax.naming.*;
import com.web_tomorrow.interest.*;
import java.util.Hashtable;
import javax.rmi.PortableRemoteObject;
import com.web_tomorrow.interest.*;
/**
This simple application tests the `Interest' Enterprise JavaBean which is
implemented in the package `com.web_tomorrow.interest'. For this to work, the
Bean must be deployed on an EJB server.
IMPORTANT If you want to test this in a real client-server
configuration, this class goes on the client; the URL of the naming provider
specifed in the class must be changed from `localhost:1099' to the URL of the
naming service on the server
*/
class InterestClient {
/**
This method does all the work. It creates an instance of the Interest EJB on
the EJB server, and calls its `calculateCompoundInterest()' method, then
prints
the result of the calculation.
*/
public static void main(String[] args) {
// Set up the naming provider; this may not always be necessary, depending
// on how your Java system is configured.
System.setProperty("java.naming.factory.initial",
"org.jnp.interfaces.NamingContextFactory");
System.setProperty("java.naming.provider.url",
"localhost:1099");
// 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();
System.out.println("Got context");
// Get a reference to the Interest Bean
// This is in the case you use the jboss.xml to override the JNDI name
Object ref = jndiContext.lookup("interest/Interest");
// If you didn't use the jboss.xml the following will work
// Object ref = jndiContext.lookup("Interest");
System.out.println("Got reference");
// Get a reference from this to the Bean's Home interface
InterestHome home = (InterestHome)
PortableRemoteObject.narrow (ref, InterestHome.class);
// Create an Interest object from the Home interface
Interest interest = home.create();
// call the calculateCompoundInterest() method to do the calculation
System.out.println
("Interest on 1000 units, at 10% per period, compounded over 2 periods
is:");
System.out.println (interest.calculateCompoundInterest (1000, 0.10, 2));
} catch(Exception e) {
System.out.println(e.toString());
}
}
}
</programlisting>
</figure>
<para>It's important to understand that in reality this client will be running
on a different computer to the Bean server. For testing you will probably run
them on the same computer, but it will still be using a network connection. So
the first part of the program indicates how to find the server. </para>
<para><programlisting>System.setProperty("java.naming.factory.initial",
"org.jnp.interfaces.NamingContextFactory");
System.setProperty("java.naming.provider.url",
"localhost:1099"); </programlisting></para>
<para>There are several other ways to do this, which you may see described in
other articles. In this case, the server is on the same machine as the client
(`localhost') and the default naming port is `1099' for JBoss (other servers
may use different port numbers). If you run the client and the server on
different machines, you will need to change these settings.</para>
<para>The comments in the program should describe how it works; one point that
requires mention is that the recommended way to get a reference to the home
interface on the server is like this: </para>
<para>
<programlisting>InterestHome home = (InterestHome)
PortableRemoteObject.narrow (ref, InterestHome.class);
</programlisting>
which ensures compatibility with different RMI servers (e.g., CORBA). `narrow'
ensures that the object returned in `ref' really can be converted to an object
of class `InterestHome'.</para>
<para>The test client doesn't need to be in the same package as the EJB
classes, and in practice it probably won't be. So it needs to import the EJB
classes using their fully-qualified class name, like this: </para>
<para>
<classname>import com.web_tomorrow.interest.*; </classname>
</para>
<para>You will also need to pay attention to the CLASSPATH when compiling.
Even though the EJB classes will run on the server, they need to be identified
to the client so that the compiler can do the appropriate type checking. In
the example program I have put the client at the top level of the directory
hierachy, so if the CLASSPATH includes the current directory it will correctly
find the EJB classes which are in the directories beneath it. </para>
<para><command>javac -classpath usr/lib/jboss/lib/ext/ejb.jar:.
InterestClient.java</command></para>
<para>This generates InterestClient.class in the current directory. </para>
</section>
<section><title>Compiling and running test client</title>
<para>We're now ready to run the test client, but first a word of
explanation.</para>
<para>In reality the client and the server are likely to be on different
computers. When you compile the client, the compiler needs to know about the
organization and methods of classes in the Bean so it can do type checking.
When you run the client, the run-time engine needs to know about the Bean
classes, because type-casting is done at run-time. So when the client attempts
to cast the remote reference to a reference to an object of class InterestHome
for example, it needs to know about this class. This means that you will need
the Bean class files on both the client and the server even though they
execute on the server. This is fairly obvious if you think about the logic,
but it causes all sorts of problems for people who are new to RMI programming.
If the client can't find the Bean classes, you will get error messages like
this:</para>
<literallayout>
<computeroutput>javax.naming.CommunicationException [Root exception is
java.lang.ClassNotFoundException: com.web_tomorrow.interest.InterestHome]
</computeroutput></literallayout>
<para>A 'communication exception' is the exception that represents any error
that can't readily be ascribed to a definite cause. If you get this message
you need to pay attention to the CLASSPATH on the client. NOTE that the server
doesn't need to have the classpath set, you just need to put it in the deploy
directory and the server will generate a ClassLoader for it.</para>
<para>If the client program is at the top of the directory hierarchy, with the
Bean classes below it, then we can run it like this:</para>
<literallayout><command>
java -classpath $$CLASSPATH:\
/usr/local/jboss/lib/ext/ejb.jar:/usr/local/jboss/client/jboss-client.jar \
InterestClient </command></literallayout>
<para>Once again, this needs to go in a shell script or a Makefile; you won't
want to type it more than once.</para>
<para>Note the long CLASSPATH; it needs to include the JBoss client classes
and the EJB classes as well as the standard classpath (if any).
If all is well, the test client produces the following output: </para>
<literallayout>
<computeroutput>
Got context
Got reference
Interest on 1000 units, at 10% per period, compounded over 2 periods is:
210.00000000000023
</computeroutput>
</literallayout>
<para>If it doesn't produce this output but you see a "MalformedURLException"
try installing jboss in another directory that doesn't contain space in it's
path (typically some installations on windows don't like C:\Program Files (the
space).</para>
<para>Another common problem you can see here is a "class not found exception"
make sure you include all the jars.</para>
<para>The Bean should produce an output on the server as well; this is to show
that the Bean has executed on the server, not the client. Look for something
like this in the server log: </para>
<para>
<computeroutput>
[Interest] Someone called `calculateCompoundInterest!'
</computeroutput>
</para>
<para>Well, that's it. We covered coding, compiling and deploying the Bean,
and coding and running a simple test client. If you found this article useful,
drop me a line at [EMAIL PROTECTED]; if there's enough response I may
be persuaded to produce some more sophisticated tutorials.</para>
</section>
</chapter>
1.1 manual/src/docs/styles.css
Index: styles.css
===================================================================
/* Background */
body { background-color: #ffffee }
/* Font selection */
ul,ol,dt,dl,th,td,h1,h2,h3,h4,p { font-family: Verdana, Arial, Helvetica, sans-serif
}
/* Font styles */
p { font-size: 10pt}
td { font-size: 12pt }
th { font-size: 12pt; font-weight: bold}
h1 { font-size: 16pt; font-weight: bold}
h2 { font-size: 14pt; font-weight: bold}
h3 { font-size: 12pt; font-weight: bold}
h4 { font-size: 10pt; font-weight: bold; font-style: italic}
/* Lists */
ul { font-size: 10pt }
ol { font-size: 10pt }
dt { font-size: 10pt }
dl { font-size: 10pt }
/* Classes */
.mediaobject { border: thin; border-style: solid; margin-right: 100% }
.programlisting { padding: 1; width: auto; margin: auto; font-family: Courier;
border-style: solid; border-width: 1; white-space: pre; background-color: #fffff7 }
.literallayout { padding: 1; width: auto; margin: auto; border-style: solid;
border-width: 1; background-color: #fffff7 }