<?xml version="1.0"?>
<document url="http://openejb.sf.net/cmp_entity_postgresql.xml" toc="numeric">
	<properties>
		<title>Custom OpenEJB Services</title>
		<sub-title>A basic (connector) service example</sub-title>
	</properties>
	<body>
		<section title="Abstract" ref-id="abstract">
<p>
<b>This an <u>advanced</u> document and is not aimed begining or 
intermediate OpenEJB users. OpenEJB users should be able to configure 
<b>any</b> JDBC datasource using the built in JDBC Connector that ships 
with OpenEJB.  To learn how to <a 
href="cmp_entity_postgresql.html#datasource">configure
a JDBC datasource.</a> follow <a 
href="cmp_entity_postgresql.html#datasource">this link.</a></b>
</p>

<p>
The aim of this document is to show OpenEJB architects what needs to be 
done in order to deploy a <a 
href="http://java.sun.com/j2ee/connector/">J2EE Connector</a>
service in OpenEJB.  The <a 
href="http://java.sun.com/j2ee/connector/">J2EE Connector Architecture</a> 
allows virtually any type of connection-oriented resource to be plugged 
into a J2EE compliant container.  As mentioned, OpenEJB already comes with 
a JDBC connector, but other implementations are possible such as a 
JavaMail connector or a Java Message Service (JMS) connector.
</p>

<p>
The goal of the OpenEJB Service Architecture is to make the lives of users 
much easier.  With the services packaged into jars, each with their own 
service-jar.xml, it is possible to package and deploy services like 
components, just as you can with EJBs.  Each service-jar.xml is synonymous 
to the ejb-jar.xml of a set of EJBs.  It contains all the information 
needed for OpenEJB to load and use the service.  It also contains the 
default configurations of all the services in the jar so that they can be 
simply dropped in and ran out-of-the-box.  
</p>

<p>
It is possible to plug-in other types of services, such as new containers, 
but this document uses a sample connector service to illustrate the ins 
and outs of creating and deploying a custom service into OpenEJB.
</p>

<p> 
Firstly, we take a deeper look at how OpenEJB configuration file -- 
openejb.conf -- looks like. It is strongly encouraged to read the <a 
href="cmp_entity_postgresql.html#datasource">Configure the data source</a> 
section in <a href="cmp_entity_postgresql.html">Hello OpenEJB World! - A 
basic CMP entity bean example</a> as you can find an introduction to it 
over there. 
</p>

<p> 
Having done that, we move on to discussing different types of OpenEJB 
services. One type is playing a great role in our example - the connector 
service. To develop our custom service we leverage what is already 
provided in OpenEJB - the existing <b>"Default JDBC Service"</b>. We don't 
want to reinvent the wheel, do we ? So, we, real Java programmers, will 
subclass the service's class to give you an insight on how to introduce a 
new functionality in the already existing OpenEJB services. Perhaps, some 
time you will create a brand new production-ready service for OpenEJB. 
That would be great. </p>

<p> 
The last section tests it out with the CMP example from <a 
href="cmp_entity_postgresql.html">Hello OpenEJB World! - A basic CMP 
entity bean example</a>. We shall see two services on the list of the 
services to choose from while deploying the bean -- one of them 
will be our newly created JDBC connector service.
</p>
</section>
		
<section title="Introduction to OpenEJB services" ref-id="introduction">
<p>
Here is a part of OpenEJB configuration file's XML Schema.  An XML 
Schema is like a DTD, but capable of doing much more validation than a 
DTD. It shows the root element of the configuration file OpenEJB will read 
at startup. 
</p>
			<code><![CDATA[
  <xsd:element name="openejb">
    <xsd:complexType mixed='true'>
      <xsd:sequence>
        <xsd:element ref="Container" maxOccurs="unbounded"/>
        <xsd:element ref="JndiProvider" minOccurs="0" maxOccurs="unbounded"/>
        <xsd:element ref="SecurityService" minOccurs="0" maxOccurs="1"/>
        <xsd:element ref="TransactionService" minOccurs="0" maxOccurs="1"/>
        <xsd:element ref="ConnectionManager" minOccurs="0" maxOccurs="1"/>
        <xsd:element ref="ProxyFactory" minOccurs="0" maxOccurs="1"/>
        <xsd:element ref="Connector" minOccurs="0" maxOccurs="unbounded"/>
        <xsd:element ref="Resource" minOccurs="0" maxOccurs="unbounded"/>
        <xsd:element ref="Deployments" minOccurs="0" maxOccurs="unbounded"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
]]></code>
<p>
As you can see there are 9 different elements OpenEJB configuration file 
can use. 7 of them represent service-specific elements -- more about those 
later. Some of them may appear more than once (e.g. Connector) and some at 
least once (e.g. SecurityService). 
</p>
<p>
The document will cover the basics about the <b>Connector</b> service type.
</p>

<p>
So, let's enter the scene by examining the Connector element. Here is 
OpenEJB's XML Schema part of the element: 
</p>
			<code><![CDATA[
  <xsd:element name="Connector">
    <xsd:complexType mixed='true'>
      <xsd:attribute name="id" type="xsd:string" use="required"/>
      <xsd:attribute name="jar" type="JarFileLocation"/>
    </xsd:complexType>
  </xsd:element>
  
  <xsd:simpleType name="JarFileLocation">
    <xsd:restriction base="xsd:string">
      <xsd:pattern value=".*\.jar$"/>
    </xsd:restriction>
  </xsd:simpleType> 
]]></code>
<p>
As the above XML Schema shows the Connector element in OpenEJB 
configuration file must consist of at least one attribute <b>id</b>. The 
id attribute is in fact a stringified pointer to the appropriate 
declaration in one of the deployed services' configuration. Strictly 
speaking, it is the name which must appear in a service's deployment 
descriptor - we will talk about it later. 
</p>

<p>
The another attribute - <b>jar</b> - is exactly the path to the jar file 
where OpenEJB expects to find the service's deployment descriptor (with 
the id name) and classes as well as other resources required by the 
service. The service's deployment descriptor is an XML file which is 
required to be available at the following paths within the service's jar 
file: 
<ul>
    <li>META-INF/service-jar.xml</li>
    <li>service-jar.xml</li>
</ul>
</p>

<note>Although all of the above paths are supported, it is highly 
recommended to use the first one - <b>META-INF/service-jar.xml</b>. The 
other is still being handled to retain backword-compatibility, but may 
disappear in future OpenEJB releases.</note> 

<p>
In its simplest form the deployment descriptor would look like as follows:
</p>

<file name="/META-INF/service-jar.xml"><![CDATA[
<?xml version="1.0"?>

<ServiceJar>
  <ServiceProvider id="PostgreSQL 7.2.1 Database"
      provider-type="Connector"
      class-name="org.acme.service.connector.PostgreSQLConnectionFactory"
  />
</ServiceJar>]]></file>
<p>
Here is a description of the simplest deployment descriptor's elements and 
attributes: 
<ul>
    <li>
        <b>id</b> - the name of a service; that is exactly the same name 
        which appears in OpenEJB configuration file as a value of a 
        service's id a ttribute
    </li> 
    <li>
        <b>provider-type</b> - the type of a service; it may be assigned 
        to one of the following types:
        
        <ul>
            <li>Container</li>
            <li>Proxy</li>
            <li>Security</li>
            <li>Transaction</li>
            <li>Connector</li>
            <li>ConnectionManager</li>
            <li>JNDI</li>
        </ul>
    </li>
    <li>
        <b>class-name</b> - the name of a class that constitutes the 
        service; the above provider-type's mandate what interfaces the 
        class must implement to become a valid candidate
    </li> 
</ul>
</p>

<p>
OpenEJB comes with several services available. Here is the list of the 
services' ids (stringified identifiers) with their short description: 
<ul>
    <li>
        <b>Default CMP Container</b> - the default Container-Managed Persistence EntityBean Container; based on Castor</li>
    <li>
        <b>Default BMP Container</b> - the default Bean-Managed Persistence EntityBean Container</li>
    <li>
        <b>Default Stateless Container</b> - the default Stateless SessionBean Container</li>
    <li>
        <b>Default Stateful Container</b> - the default Stateful SessionBean Container</li>
    <li>
        <b>Default JDK 1.2 ProxyFactory</b> - the default Proxy Factory implementation for JDK 1.2</li>
    <li>
        <b>Default JDK 1.3 ProxyFactory</b> - the default Proxy Factory implementation for JDK 1.3</li>
    <li>
        <b>Default Security Service</b> - the default Security Service implementation</li>
    <li>
        <b>Default Transaction Manager</b> - the default Transaction Manager implementation</li>
    <li>
        <b>Default JDBC Database</b> - the default JCA ManagedConnectionFactory for JDBC</li>
    <li>
        <b>Default Local TX ConnectionManager</b> - the default JCA ConnectionManager</li>
</ul>

The services' default configuration file is included as 
<b>default.service-jar.xml</b> in the %OPENEJB_HOME%/lib/openejb-x.x.x.jar 
file. 
</p>
</section>

<section title="Developing a service" ref-id="development">
<p>
After the introductory material let's delve our hands into the real stuff 
-- programming. The following steps will lead you through the bumpy road 
of OpenEJB services programming making it easy like never before. 
</p>

<p>
The service you are about to create is a Connector service named 
"PostgreSQL 7.2.1 Database". The purpose of the service is to carry out 
our custom name (so we could name it as we want), handle an additional 
service-specific parameter and finally refuse to connect to other 
databases than PostgreSQL unless the parameter mandates otherwise. Quite 
enough as a starter -- after all, this was meant to be a basic service 
example.
</p>

<p>
So, let's name our brand new service "PostgreSQL 7.2.1 Database". As it 
has been described in the previous section, the name shall appear in the 
service's deployment descriptor in META-INF/service-jar.xml. It is simply 
a value of the id attribute of the ServiceProvider's element. 
</p>

<p>
The service's functionality is to provide PostgreSQL connections. It does 
represent a Connector service; thus, the provider-type is "Connector".
</p>

<p>
The last attribute to assign a value to is class-name. The class must 
reflect the functionality OpenEJB expects from connectors, i.e. it must 
implement <b>javax.resource.spi.ManagedConnectionFactory</b> class. Our 
class extends the already available OpenEJB class - 
<b>org.openejb.resource.jdbc.JdbcManagedConnectionFactory</b>, which 
represents "Default JDBC Database" service. 
</p>

<p>
All the text between the &lt;ServiceProvider&gt; and 
&lt;/ServiceProvider&gt; tags of the service's declaration 
in the service-jar.xml will be intepreted as properties and will be passed 
into the service by OpenEJB as an instance of java.util.Properties when 
OpenEJB starts up.  Service providers should use this area to set 
default values for all the configurable properties the service has.  The 
format of the text between the &lt;ServiceProvider&gt; and 
&lt;/ServiceProvider&gt; tags can be any text valid for a Java propeties 
file.  The properties themselves can be anything that the Service provider 
wants. 
</p> 

<p>
Users can easily reconfigure the service by specifying new values for the 
properties in the openejb.conf.  This overrides the properties in the 
service's service-jar.xml and allows users to reconfigure the service 
without having to mess with the service's jar and service-jar.xml file.
</p> 

<p>
In the case of our Connector, users can override the default property 
values we set in our service-jar.xml by going to the &lt;Connector&gt; and 
&lt;/Connector&gt; tags in their openejb.conf file and typing in new 
properties and values.
</p> 

<p>
An elegant aspect of this approach is that users can create as many 
"profiles" or configurations of OpenEJB and it's services by simply 
creating an openejb.conf file for each.  For example, a user might have 
the following config files in their conf/ directory:
<ul>
    <li>development_openejb.conf</li>
    <li>test.openejb.conf</li>
    <li>my.production-openejb.conf</li>
    <li>no-cmp-container.openejb.conf</li>
</ul>
</p>

<p>
Create the directory where the service's files are located.
</p>

<command>C:\> mkdir C:\my\app\org\acme\service\connector</command>
<br/>
<command>C:\> cd C:\my\app</command>
			
<p>In your favorite editor, create the file below.</p>

<p>
<code name="C:\my\app\org\acme\service\connector\PostgreSQLConnectionFactory.java">
package org.acme.service.connector;

import org.openejb.resource.jdbc.JdbcManagedConnectionFactory;

import javax.resource.ResourceException;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ManagedConnection;
import javax.resource.spi.ResourceAdapterInternalException;
import javax.security.auth.Subject;
import java.util.Properties;

public class PostgreSQLConnectionFactory extends JdbcManagedConnectionFactory
{
   public static final String STRICT_PROPERTY_NAME = "strict";

   /**
    * Allow only PostgreSQL drivers,
    * i.e. those that belong to org.postgresql package
    */
   private boolean strict = true;

   public PostgreSQLConnectionFactory()
   {
      System.out.println( "+++ Message from PostgreSQLConnectionFactory.&lt;init&gt;" ); 
   }

   public void init( Properties props )
           throws ResourceAdapterInternalException
   {
      System.out.println(
          "+++ Message from PostgreSQLConnectionFactory.init( Properties props ) method" );

      super.init( props );

      setStrict( props.getProperty( STRICT_PROPERTY_NAME ) );
   }

   public void setStrict( String strict )
   {
      this.strict = !"false".equalsIgnoreCase( strict );
      System.out.print( "+++ Setting up [" + STRICT_PROPERTY_NAME + "]");
      System.out.println( " to [" + this.strict + "]" );
   }

   public ManagedConnection createManagedConnection( Subject subject,
                                                     ConnectionRequestInfo cxRequestInfo )
           throws ResourceException
   {
      System.out.println( "+++ createManagedConnection() is being called" );
      
      <comment>// if strict is not set explicitly or it sets to true</comment>
      <comment>// and the driver doesn't belong to org.postgresql package</comment>
      <comment>// refuse the request for creating a new connection</comment>
      if ( this.strict &amp;&amp; !getJdbcDriver().startsWith( "org.postgresql" ) )
      {
         throw new ResourceAdapterInternalException(
                 "", "+++ The driver " + getJdbcDriver() + " is not PostgreSQL driver" );
      }
      System.out.print("+++ createManagedConnection() - the driver ");
      System.out.println( getJdbcDriver() + " passed the test" );
              
      <comment>// the method returns a new physical connection</comment>
      return super.createManagedConnection( subject, cxRequestInfo );
   }
}</code>
</p>

<command>C:\my\app> mkdir META-INF</command>

<p>In your favorite editor, create the file below.</p>

<p>
				<file name="C:\my\app\META-INF\service-jar.xml"><![CDATA[
<?xml version="1.0"?>

<ServiceJar>
  <ServiceProvider id="PostgreSQL 7.2.1 Database"
        provider-type="Connector"
        class-name="org.acme.service.connector.PostgreSQLConnectionFactory"
  />
# The default properties of the connector
JdbcDriver = org.postgresql.Driver
JdbcUrl = jdbc:postgresql://localhost/mydb
UserName = username
Password = password
strict = true
</ServiceJar>]]></file>
</p>
</section>
		
<section title="Packaging a service" ref-id="packaging">
<p>
This step boils down to compiling the class and creating the jar file 
using the following commands: 
</p>

<command>C:\my\app> set CP=%OPENEJB_HOME%\lib\ejb-2.0.jar</command>
<br/>
<command>C:\my\app> set CP=%CP%;%OPENEJB_HOME%\lib\jaas_1.0.jar</command>
<br/>
<command>C:\my\app> set CP=%CP%;%OPENEJB_HOME%\lib\jca_1.0.jar</command>
<br/>
<command>C:\my\app> set CP=%CP%;%OPENEJB_HOME%\dist\openejb-0.8.1.jar</command>
<br/>
<command>C:\my\app> javac -d . -classpath %CP% org\acme\service\connector\*.java</command>
<br/>
<command>C:\my\app> jar -cvf postgresql-service.jar org\acme\service\connector\*.class META-INF</command>
</section>
		
<section title="Deploying a service" ref-id="deploying">
<p>
Before using a service in OpenEJB it has to be deployed first. The process 
involves modyfing OpenEJB configuration file, i.e. openejb.conf. The 
following file is the one being used in <a 
href="cmp_entity_postgresql.html#datasource">Configure the data source</a> 
section in <a href="cmp_entity_postgresql.html">Hello OpenEJB World! - A 
basic CMP entity bean example</a> with the necessary changes pertaining to 
our service (note the id attribute has changed as well as the jar 
attribute and struct parameters have been added). 
</p>
<p>
Create the file in the conf directory.
</p>

<p>
<command>C:\my\app> mkdir conf</command>
</p>

<p>
In your favorite editor, create the file below.
</p>

<file name="C:\my\app\conf\openejb.xml"><![CDATA[
<?xml version="1.0"?>

<openejb>
  <Container id="Default CMP Container" ctype="CMP_ENTITY">
    Global_TX_Database  c:/my/app/conf/postgresql.cmp_global_database.xml
    Local_TX_Database   c:/my/app/conf/postgresql.cmp_local_database.xml
  </Container>
  <Deployments jar="c:/my/app/employee.jar"/>
  <Connector id="PostgreSQL 7.2.1 Database" jar="c:/my/app/postgresql-service.jar">
    # override this property to point to an
    # actual database -- the acme_db
    JdbcUrl jdbc:postgresql://localhost/acme_db
    
    # override these two properties to 
    # specify an actual user authorized to
    # access acme_db
    UserName roadrunner
    Password beepbeep
  </Connector>
  <SecurityService id="Default Security Service"/>
  <TransactionService id="Default Transaction Manager"/>
</openejb>
]]></file>
</section>

<section title="Using a service" ref-id="using">
<p>
Depending on the service type its usage may vary. In case of our Connector 
service, we leverage the sample entity bean described in <a 
href="cmp_entity_postgresql.html">Hello OpenEJB World! - A basic CMP 
entity bean example</a> document. The sample needs to have a connector 
service configured in OpenEJB before being deployed. Our service is an 
excellent candidate. 
</p>

<note>
The <a href="cmp_entity_postgresql.html#datasource">Configure the data 
source</a> section ought to embrace the configuration file from the <a 
href="#deploying">Deploying a service</a> section above. 
</note>

<p>
While performing this step you ought to see the following output on 
OpenEJB console: 
</p>
<code><![CDATA[
OpenEJB Remote Server 0.8.1    build: 20020731-0133
http://openejb.sf.net
----------------STARTUP----------------
[init] OpenEJB Container System
+++ Message from PostgreSQLConnectionFactory.<init>
+++ Message from PostgreSQLConnectionFactory.init( Properties props ) method
+++ Setting up [strict] to [true]
[init] OpenEJB Remote Server
  ** Starting Services **
  NAME             IP              PORT
  ejb server       127.0.0.1       4201
  admin console    127.0.0.1       4200
-----------------INFO------------------
To log into the admin console, telnet to:
 telnet 127.0.0.1 4200
---------------------------------------
Ready!
+++ createManagedConnection() is being called
+++ createManagedConnection() - the driver org.postgresql.Driver passed the test
[Jacek Laskowski(5) OpenEJB-1030222628219@SF.net] Hello OpenEJB World!]]></code>

<p>
The above lines, which begin with '+++' are those from the PostgreSQL 
7.2.1 Database service. It should get you a feeling on how OpenEJB 
initializes services, i.e. what service's methods are being invoked upon 
OpenEJB startup. 
</p>

<note>
Change the <b>JdbcDriver</b> parameter to any class like 
<b>java.lang.String</b> to see the failure when OpenEJB refuses to create 
a connection because of the invalid driver class. 
</note>
</section>
		
<section title="What if it didn't work" ref-id="problems">
<p>
If you ran into any problems, first check your openejb.log file at 
%OPENEJB_HOME%\openejb.log. Look for any lines that begin with 
<term>"WARN"</term>, <term>"ERROR"</term>, or <term>"FATAL"</term>. 
</p>

<p>
There is a list of the most common problems with possible solutions: 
<ul>
<li>
<p><b>Problem:</b></p>
<code><![CDATA[
OpenEJB Remote Server 0.8.1    build: 20020731-0133
http://openejb.sf.net
----------------STARTUP----------------
[init] OpenEJB Container System
Message from PostgreSQLConnectionFactory.<init>
java.lang.ClassNotFoundException: org.postgresql.Driver
        at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
        at java.security.AccessController.doPrivileged(Native Method)
        ...
]]></code>
<p><b>Solution:</b></p>
<p>Add the PostgreSQL JDBC2 driver to OpenEJB's 
CLASSPATH. See the <a href="#datasource">Configure the data source</a> section for more details.
</p>
</li>
</ul>
</p>
</section>
</body>
</document>
