<document>
<header>
<product>resin-ee</product>
<resin-2.0>$ee/ejb-tut/ejb-hello.xtp</resin-2.0>
<type>tutorial</type>
<tutorial-startpage>index.jsp</tutorial-startpage>
<title>Stateless Session Hello</title>
<description>

<p>This example creates a <var/stateless session/> bean.  A stateless session
bean is similar to a servlet without sessions.  The server bean itself can have
state, but doesn't remember the client from one request to the next.</p>

<p>A Hello, World example for EJB is fairly complicated.  To implement the EJB
you need to implement:</p>

<ul>
<li>A remote interface
<li>A home interface
<li>The bean implementation
<li>a deployment descriptor
</ul>

<p>To configure Resin to be a server for the EJB you need to:</p>

<ul>
<li>Configure the ejb-server
<li>Configure a protocol
</ul>

<p>To use the EJB from a client you need to:</p>
<ul>
<li>Create a factory for the correct protocol
<li>Obtain a Home
<li>Use the Home to create stubs to the remote object
</ul>

<p>In this tutorial, a simple "Hello" EJB is created and deployed within Resin. The use of the Hello EJB from a client is also demonstrated.</p>

</description>
</header>

<body>
<summary/>

<section title="Remote Interface">

<p>The remote interface defines the client view of the bean.
It extends <var/EJBObject/> and declares all the business methods.  Our
only business method is the <code/hello/> method.</p>

<example title="Hello.java" file="WEB-INF/classes/example/Hello.java">
package example;

import java.rmi.*;
import javax.ejb.*;

public interface Hello extends EJBObject {
  public String hello() throws RemoteException;
}
</example>

</section>

<section title="Home Interface" file="WEB-INF/classes/example/Hello.java">

<p>The sole responsibility of the Home interface is to create a
remote object.  The client uses the Home to obtain instances of the bean.</p>

<example title="HelloHome.java" file="WEB-INF/classes/example/HelloHome.java">
package example;

import java.rmi.*;
import javax.ejb.*;

public interface HelloHome extends EJBHome {
  public Hello create() throws RemoteException, CreateException;
}
</example>

</section>

<section title="Bean Implementation">

<p>The third class for EJB's is the bean implementation class.  It implements
the functionality provided by the remote interface.</p> 

<p>A stateless session bean needs to have exactly one <var/ejbCreate/>
method with no arguments.  It must also define the business methods.</p>

<p>The bean implementation class for all EJB Session bean's must implement the
SessionBean interface.  Most users will create a com.foo.AbstractSessionBean
class that provides default method implementations.  This example
extends Resin's AbstractSessionBean to simplify the implementation.</p>

<example title="HelloBean.java" file="WEB-INF/classes/example/HelloBean.java">
package example;

import java.rmi.*;
import javax.ejb.*;

public class HelloBean extends com.caucho.ejb.AbstractSessionBean {
  public void ejbCreate()
  {
  }

  public String hello()
  {
    return "Hello, world";
  }
}
</example>

</section>

<section title="Deployment descriptor">

<p>A deployment descriptor is used to describe and define the EJB bean.  In
general, configuration of EJB's belongs in an <var/ejb-jar.xml/> file.  In a
jar, it belongs in <var/META-INF/ejb-jar.xml/>.</p>

<p>This name, of course, only makes sense if the EJB is put into a jar.  Jars
are inconvenient during development, so Resin lets you rename the ejb-jar.xml
file as *.ejb and put it in WEB-INF.  We'll name it <var/WEB-INF/hello.ejb/>.
You can have as many *.ejb files as you want, Resin will use them all (for
example WEB-INF/hello.ejb, WEB-INF/goodbye.ejb).</p>

<p><var/&lt;ejb-jar&gt;/> is the top element for a deployment descriptor for
the bean.  It's part of the EJB spec.  The configuration for the stateless
session example looks like the following:</p>

<example title="hello.ejb" file="WEB-INF/hello.ejb">
&lt;ejb-jar&gt;
&lt;enterprise-beans&gt;
  &lt;session&gt;
    &lt;ejb-name&gt;hello&lt;/ejb-name&gt;
    &lt;home&gt;example.HelloHome&lt;/home&gt;
    &lt;remote&gt;example.Hello&lt;/remote&gt;
    &lt;ejb-class&gt;example.HelloBean&lt;/ejb-class&gt;
    &lt;session-type&gt;Stateless&lt;/session-type&gt;
    &lt;transaction-type&gt;Bean&lt;/transaction-type&gt;
  &lt;/session&gt;
&lt;/enterprise-beans&gt;  
&lt;/ejb-jar&gt;
</example>

<deftable>
<tr><th>Tag<th>Meaning
<tr><td>ejb-jar<td>containing XML tag for the whole ejb-jar
<tr><td>enterprise-beans<td>another container for the beans
<tr><td>session<td>define a session bean
<tr><td>ejb-name<td>the bean's name.  <var/hello/> is part of the URL.
<tr><td>home<td>the home interface class
<tr><td>remote<td>the remote interface class
<tr><td>ejb-class<td>the implementation class
<tr><td>session-type<td>Stateless is like a servlet without sessions
<tr><td>transaction-type<td>Transactions.  For now, you can ignore this.
</deftable>

</section>

<section title="Configuring the Resin EJB server">

<p>All of the above steps are needed to define and implement an EJB.  Once the
bean has bean defined and implemented, it is deployed within the Resin server.
Through deployment, Resin becomes aware of the EJB and how it is meant to be
used.</p>

<p><code>&lt;ejb-server&gt;</code> is used to configure the Resin EJB server.
The EJB server is responsible for reading the *.ejb descriptor files
and deploying the beans within the server.</p>

<example title="ejb-server in web.xml"
         file="WEB-INF/web.xml"
         re-start="<ejb-server">
&lt;web-app&gt;

  ...

  &lt;ejb-server config-directory="WEB-INF"/&gt;
    
  ...

&lt;/web-app&gt;
</example>

<p>The ejb-server automatically searches for all *.ejb files in WEB-INF.  It
will find the hello.ejb file and deploy the "hello" EJB bean.</p>

</section>

<section title="Configuring the protocol">

<p>The server needs to make the EJB's available to remote clients using a
<var/protocol/>.  The protocol defines the language that is used by the client
and the server to communicate.</p>

<p>This example uses the Hessian EJB Servlet to make the EJB's available to
remote clients using the <var/Hessian protocol/>.</p>

<example title="Configuring hessian in web.xml"
         file="WEB-INF/web.xml"
         re-start="='/?hessian" re-end="='/?hessian">
&lt;web-app&gt;

  ...

  &lt;ejb-server config-directory="WEB-INF"/&gt;
    
  &lt;servlet servlet-name='hessian' servlet-class='com.caucho.hessian.EJBServlet'/&gt;   
  &lt;servlet-mapping url-pattern='/hessian/*' servlet-name='hessian'/&gt;

  ...

&lt;/web-app&gt;
</example>

<p>When the EJB is used by a Hessian client, the client adds the
<var/ejb-name/> from the hello.ejb file to the url that points to the Hessian
servlet.  In this example, it is
<var/http://localhost:8080/hessian/hello/>.</p> 

</section>

<section title="Client">

<p>The whole point of EJB stateless session beans is to provide a means of
communication between a client and a server.  Typically, the client will be on
a different machine, or at least a different Java virtual machine, than the
server.</p>

<p>The client needs to be provided with some things to be able to accomplish
this.  It needs:</p>
<ul>
<li>The Home interface (HelloHome.class)
<li>The Remote interface (Hello.class)
<li>A library of the standard ejb classes
<li>A library of classes that implement the protocol being used
</ul>

<p>EJB clients perform the following steps in obtaining and using a remote
object:</p>
<ol>
<li>Create a protocol-specific <var/factory/> that is used to obtain Home objects from the remote server
<li>Use the factory to obtain a <var/home/> for a particular ejb.
<li>Use the home to create a <var/remote object stub/>.
<li>Call business methods on the remote object stub.
</ol>

<p>The factory is the link between the client and the server. Once the factory
is created, it is used to obtain Home's for particular EJB's.  The factory, and
the Home's, do not change,  Usually the factory and the Home for each EJB are
created once and then stored for future use.  An applet, for example, creates
the factory on startup and stores it as a member variable.  Individual classes within the applet, that need particular Home's, create them once and store them as member variables.</p>

<p>The home is used to create a stub to a particular remote instance of an
object.  A stub is a placeholder or proxy object.  The client uses the stub
just like any other object, the actual execution of the methods provided by the
stub happens on the server.</p>

<p>In this example, the client is a servlet and the Home is obtained in the
init() method and stored as a member variable.  A <code/HessianProxyFactory/>
is created and then used to obtain the HelloHome for the Hello ejb.  </p>

<p>The url of the server is passed as an init-param to the servlet.  This
allows for easy configuration if the url of the server adress changes.  The
reulsting url that is passed to the factory will look something like
<code>http://localhost:8080/hessian/home</code>.</p>

<example file="WEB-INF/classes/example/HelloServlet.java"
         re-start="(HessianProxyFactory;|private HelloHome|void init)" re-end="(HessianProxyFactory;|private HelloHome|^  })">
  private HelloHome helloHome;

  public void init(ServletConfig config)
    throws ServletException
  {
    super.init(config);

    serverUrl = config.getInitParameter("java.naming.provider.url");

    if (serverUrl == null)
      throw new ServletException("init-param java.naming.provider.url is required");

    if (!serverUrl.endsWith("/"))
      serverUrl = serverUrl + "/";

    try {
      HessianProxyFactory factory = new HessianProxyFactory();
      helloHome = (HelloHome) factory.create(HelloHome.class, serverUrl + "hello");
    } catch (Exception e) {
      throw new ServletException(serverUrl + "hello", e);
    }
  }

</example>
</section>
    

<section name="jndi-client" title="JNDI client">

<p>The preceding example used Hessian directly.  This is a good idea for
applets or other clients that do not have good support for the use of JNDI.</p>

<p>More often, clients will use <var/JNDI/>, the Java Naming and Directory
Interface, to get the Home.  JNDI is used to configure the <var/factory/>, the
factory is obtained with a JNDI lookup and is used to obtain Home's for the
different EJB's.</p>

<p>JNDI is based on naming <var/contexts/>.  Contexts are like
paths on a file system, but store objects instead of files.
By convention, the path <var/java:comp/env/ejb/> is used for EJB.</p>

<section title="JNDI-based client configuration">

<p>Typically, the client will be on a different machine, or at least a
different Java virtual machine, than the server.  Each client environment will
provide a different means of configuring a JNDI factory.</p>

<p>Resin uses <code/jndi-link/> to configure the JNDI factory.</p>

<p>The url of the server is passed as an init-param to the
HessianContextFactory.  This allows for easy configuration if the url of the
server address changes.</p>

<example file="WEB-INF/web.xml"
         title="Resin JNDI client configuration"
         re-start="<jndi-link" re-end="</jndi-link">
&lt;web-app&gt;

  ...

  &lt;jndi-link jndi-name='java:comp/env/ejb'
             factory='com.caucho.hessian.HessianContextFactory'&gt;
    &lt;init-param java.naming.provider.url='http://localhost:8080/hessian'/&gt;
  &lt;/jndi-link&gt;

  ...

&lt;/web-app&gt;
</example>

<p><code>HessianContextFactory</code> can be used in any server or other Java
environment that supports JNDI.</p>

</section> <!-- jndi client config -->

<section title="JNDI-based client code">

<p>The client code does a JNDI lookup to get the factory. As in the previous
client example, the client is a servlet and the Home is obtained in the init()
method and stored as a member variable.</p>

<p>Only the init() method is differet in the HelloJndiServlet, the rest of the
class is identical to the previous HelloServlet.</p>

<example file="WEB-INF/classes/example/HelloJndiServlet.java"
         re-start="(naming\.|private HelloHome|void init)" re-end="(naming\.|private HelloHome|^  })">

  private HelloHome helloHome;

  public void init(ServletConfig config)
    throws ServletException
  {
    super.init(config);

    try {
      Context ejb = (Context) new InitialContext().lookup("java:comp/env/ejb");
      helloHome = (HelloHome) ejb.lookup("hello");

    } catch (NamingException e) {
      throw new ServletException("java:comp/env/ejb",e);
    }
  }

</example>

</section> <!-- jndi client code -->


</section>

</body>
</document>
