JBOSS, MS Access &
Entity Beans
When I
followed the tutorial at www.ejbtut.com I
used an application server called Blazix. At my company we use JBoss, though
Blazix is easy to operate. Unfortunately�
the information about how to use ODBC with JBOSS was scares. Hopefully
this paper will better inform you how to do it.
The
document is not a �dummy tutorial�, because first of all you have to have above
average knowledge of programming and second of all it is not really a tutorial.
There was not enough time for that.
Edgar de Graaf
[EMAIL PROTECTED]
With help
of Ordina.
Feel free
to comment.
First thing first
This
document begins with the following assumptions:
- You know how to set-up ODBC.
- You know enough about Java
Technology: EJB, JDBC en Java in general.
- You have knowledge of XML.
- You know what port, url and
servers are.
- You have installed
JBoss(version 3).
- Knowledge of databases, in
particular MS Access.
This paper
is not about installing JBoss, besides that�s easy!
Making the connection
First we
are going to modify Jboss.jcml. This file can be found in the conf
directory in Jboss. Now search for the for the JdbcProvider. You will jump to:
<mbean code="org.jboss.jdbc.JdbcProvider"
name="DefaultDomain:service=JdbcProvider">
<attribute
name="Drivers">org.hsqldb.jdbcDriver,
sun.jdbc.odbc.JdbcOdbcDriver</attribute>
�</mbean>
If sun.jdbc.odbc.JdbcOdbcDriver
is not there then add it. It will look like the example above.
Behind the
</mbean> tag add the following code:
<mbean
code="org.jboss.jdbc.XADataSourceLoader"
����� �
name="DefaultDomain:service=XADataSource,name=MSAccess">
<attribute
name="DataSourceClass">org.jboss.pool.jdbc.xa.wrapper.XADataSourceImpl</attribute>
<attribute
name="PoolName">MSAccess</attribute>
<attribute
name="URL">jdbc:odbc:StockOdbc</attribute> <attribute
name="JDBCUser"></attribute>
<attribute name="Password" />
<attribute
name="LoggingEnabled">false</attribute>
</mbean>
Save and
close jboss.jcml.
Construct a
MS Access database called Stock.mdb with the table Stock. The table
Stock has two columns: Name and Value. Name must be Text and Value a
Number.� Now add an Odbc connection to
the Stock.mdb. Call the Odbc StockOdbc.
Assembling the EJB.
The EJB
must have all its classes in a jar. Besides that it has to have some
configuration XML files: ejb-jar.xml, jaws.xml and jboss.xml. Those files MUST
be in the META-INF directory.
Jaws.xml
takes care of describing which datasource the EJB should use.
Now make
your EJB:
import javax.ejb.*;
import javax.naming.*;
import java.rmi.*;
public class StockBean implements
javax.ejb.EntityBean {
����� public
String name = null;
����� public
Integer value = null;
����� EntityContext
ejbEntityContext = null;
����� public String getName()
����� {
����� ����� return name;
����� }
����� public
Integer getValue()
����� {
����� ����� return value;
����� }
����� public
void setValue ( Integer value )
����� {
����� ����� this.value = value;
����� }
����� public
String ejbCreate(String name, Integer value)
����������� ����������� ����� throws
CreateException, RemoteException
����� {
����� ����� this.name = name;
����� ����� this.value = value;
����� ����� return null;
����� }
����� public
void setEntityContext( javax.ejb.EntityContext ejbEntityContext )
����� ����� throws RemoteException
����� {
����� ����� this.ejbEntityContext = ejbEntityContext;
����� }
����� public
void unsetEntityContext()
����� ����� throws RemoteException
����� {
����� ����� this.ejbEntityContext = null;
����� }
����� public
void ejbPostCreate( String name, Integer value )
����� {
����� }
����� public
void ejbRemove()
����� ����� throws RemoteException, RemoveException
����� {
����� }
����� public
void ejbActivate()
����� ����� throws RemoteException
����� {
����� }
����� public
void ejbPassivate()
����� ����� throws RemoteException
����� {
����� }
����� public
void ejbLoad()
����� ����� throws RemoteException
����� {
����� }
����� public
void ejbStore()
����� ����� throws RemoteException
����� {
����� }
}
Construct
the home interface:
import javax.ejb.*;
import javax.naming.*;
import java.rmi.*;
public interface StockHome extends
javax.ejb.EJBHome {
����� Stock
create( String name, Integer value )
����� ����� throws javax.ejb.CreateException,
RemoteException;
����� Stock
findByPrimaryKey( String pkey ) throws FinderException, RemoteException;
����� java.util.Collection
findValueEquals ( Integer value ) throws FinderException, RemoteException;
}
And the
interface:
import javax.ejb.*;
import java.rmi.*;
public interface Stock extends
javax.ejb.EJBObject {
����� java.lang.String
getName() throws RemoteException;
����� java.lang.Integer
getValue() throws RemoteException;
����� void
setValue( Integer value) throws RemoteException;
}
Now compile
this Java source code.
Construct
the following configuration files:
Jaws.xml
<?xml version="1.0"
encoding="UTF-8"?>
<jaws>
���
<datasource>java:/MSAccess</datasource>
���
<type-mapping>MS ACCESS</type-mapping>
���
<debug>true</debug>
��� <enterprise-beans>
����������� ����� <entity>
����������� ����������� �<ejb-name>Stock</ejb-name>
����������� ����������� �<cmp-field><field-name>name</field-name>
<column-name>Name</column-name></cmp-field>
����������� ����������� �<cmp-field><field-name>value</field-name
><column-name>[Value]</column-name></cmp-field>
����������� ����������� �<create-table>false</create-table>
����������� ����������� �<remove-table>false</remove-table>
����������� ����������� �<read-only>false</read-only>
����������� ����������� �<time-out>300</time-out>
����������� ����������� �<select-for-update>false</select-for-update>
����������� ����������� �<finder>
����������� ����������� ����� ����� <name>findValueEquals</name>
����������� ����������� ����� ����� <query>value = {0}</query>
����������� ����������� ����� ����� <order>value DESC</order>
����������� ����������� ����� ����� <read-ahead>false</read-ahead>
������ ���� ������ ����� </finder>
����������� ����� </entity>
����� ����� </enterprise-beans>
</jaws>
Jboss.xml
<?xml version="1.0"
encoding="Cp1252"?>
<jboss>
���
<secure>false</secure>
��� <container-configurations />
��� <resource-managers />
��� <enterprise-beans>
������� <entity>
����������� ���
<ejb-name>Stock</ejb-name>
����������� ���
<jndi-name>jaws/Stock</jndi-name>
�������
</entity>
���
</enterprise-beans>
</jboss>
Finally ejb-jar.xml
<?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>
<description>
ejb-jar.xml file for entity bean Stock
</description>
<enterprise-beans>
<entity>
<description>
Entity bean Stock
</description>
<ejb-name>Stock</ejb-name>
<home>StockHome</home>
<remote>Stock</remote>
<ejb-class>StockBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>True</reentrant>
<cmp-field><field-name>name</field-name></cmp-field>
<cmp-field><field-name>value</field-name></cmp-field>
<primkey-field>name</primkey-field>
</entity>
</enterprise-beans>
</ejb-jar>
Now jar all
those files. Remember those XML files MUST be in the META-INF directory.
Place the JAR in the deploy directory of JBoss.
Mapping types
To make
this EJB work you should change the standardjaws.xml in the conf directory of JBoss.
Add the following type mapping� before
the </type-mappings> tag:
<type-mapping>
����� ����� <name>MS ACCESS</name>
����� ����� <mapping>
����������� ����� ����� <java-type>java.lang.Byte</java-type>
����������� ����� ����� <jdbc-type>SMALLINT</jdbc-type>
����������� ����� ����� <sql-type>SMALLINT</sql-type>
����� ����� </mapping>
����� ����� <mapping>
����������� ����� ����� <java-type>java.util.Date</java-type>
����������� ����� ����� <jdbc-type>DATE</jdbc-type>
����������� ����� ����� <sql-type>DATE</sql-type>
����� ����� </mapping>
����� ����� <mapping>
����������� ����� ����� <java-type>java.lang.Boolean</java-type>
����������� ����� ����� <jdbc-type>BIT</jdbc-type>
����������� ����� ����� <sql-type>BIT</sql-type>
����� ����� </mapping>
����� ����� <mapping>
����������� ����� ����� <java-type>java.lang.Integer</java-type>
����������� ����� ����� <jdbc-type>INTEGER</jdbc-type>
����������� ����� ����� <sql-type>INTEGER</sql-type>
����� ����� </mapping>
����� ����� <mapping>
����������� ����� ����� <java-type>java.lang.Object</java-type>
����������� ����� ����� <jdbc-type>JAVA_OBJECT</jdbc-type>
����������� ����� ����� <sql-type>OBJECT</sql-type>
����� ����� </mapping>
����� ����� <mapping>
����������� ����� ����� <java-type>java.lang.Short</java-type>
����������� ����� ����� <jdbc-type>SMALLINT</jdbc-type>
����������� ����� ����� <sql-type>SMALLINT</sql-type>
����� ����� </mapping>
����� ����� <mapping>
����������� ����� ����� <java-type>java.lang.Character</java-type>
����������� ����� ����� <jdbc-type>CHAR</jdbc-type>
����������� ����� ����� <sql-type>CHAR</sql-type>
����� ����� </mapping>
����� ����� <mapping>
����������� ����� ����� <java-type>java.lang.String</java-type>
����������� ����� ����� <jdbc-type>VARCHAR</jdbc-type>
����������� ����� ����� <sql-type>TEXT</sql-type>
����� ����� </mapping>
����� ����� <mapping>
����������� ����� ����� <java-type>java.sql.Timestamp</java-type>
����������� ����� ����� <jdbc-type>TIMESTAMP</jdbc-type>
����������� ����� ����� <sql-type>TIMESTAMP</sql-type>
����� ����� </mapping>
����� ����� <mapping>
����������� ����� ����� <java-type>java.lang.Float</java-type>
����������� ����� ����� <jdbc-type>REAL</jdbc-type>
����������� ����� ����� <sql-type>FLOAT</sql-type>
����� ����� </mapping>
����� ����� <mapping>
����������� ����� ����� <java-type>java.lang.Long</java-type>
����������� ����� ����� <jdbc-type>BIGINT</jdbc-type>
����������� ����� ����� <sql-type>LONG</sql-type>
����� ����� </mapping>
����� ����� <mapping>
����������� ����� ����� <java-type>java.lang.Double</java-type>
����������� ����� ����� <jdbc-type>DOUBLE</jdbc-type>
����������� ����� ����� <sql-type>DOUBLE</sql-type>
����� ����� </mapping>
</type-mapping>
Constructing the client
Now
constuct the following client application:
// EntityClientSample.java
// Sample program showing entity bean usage.
//
import javax.naming.*;
import javax.ejb.*;
import java.util.*;
import Stock.*;
public class StockClient {
���
static public void main( String[] args )
��� {
�������
checkArgs( args );
�������
try {
�����������
// Obtain the EJB home
�����������
Properties env = new Properties();
�����������
env.put( "java.naming.factory.initial",
���������������
"org.jnp.interfaces.NamingContextFactory" );
�����������
env.put( "java.naming.provider.url",
���������������
"jnp://localhost:1099" );
�����������
env.put(
"java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces");
�����������
Context ctx = new InitialContext( env );
�����������
StockHome home = (StockHome) ctx.lookup( "jaws/Stock" );
�����������
Stock bean;
�����������
if ( doGet ) {
���������������
try {
������������������� bean = home.findByPrimaryKey( stock );
������������������� System.out.println( stock + ": " +
bean.getValue());
�����������
����} catch (FinderException
notFound) {
������������������� System.out.println( "Property
\"" + stock + "\" was not found" );
���������������
}
�����������
}
�������
else if ( doGetValue ) {
����������� ����� ����� try
{
����������� ����������� ����� Collection
coll = home.findValueEquals( value );
����������� ����������� ����� Iterator
collItr = coll.iterator();
����������� ����������� ����� while(collItr.hasNext()){
����������� ����������� ����� ����� bean = (Stock) collItr.next();
����������� ����������� ����� ����� System.out.println( "Stock name :
" + bean.getName());
����������� ����������� ����� }
����������� ����� ����� }
catch (FinderException notFound) {
����������� ����������� ����� System.out.println(
"Property was not found" );
����������� ����� ����� }
����������� ����� ����� }
����������� ����� ����� else
{
����������� ����������� ����� ����� System.out.println("Setting
value");
����������� ����������� ����� ����� try {
����������� ����������� ����������� ����� ����� bean
= home.create( stock, value );
����������� ����������� ����� ����� } catch (DuplicateKeyException exists) {
����������� ����������� ����������� ����� ����� bean
= home.findByPrimaryKey( stock );
����������� ����������� ����� ����� }
����������� ����������� ����� ����� bean.setValue( value );
����������� ����������� ����� ����� System.out.println( "Set value of
\"" + stock + "\" to \"" + value +
"\"" );
����������� ����� ����� }
������� }
catch (Exception ex) {
�����������
ex.printStackTrace();
������� }
��� }
���
static void usage()
��� {
�������
System.out.println( "Usage: java StockClient put <stock-name>
<value>" );
�������
System.out.println( "Usage: java StockClient getValue
<value>" );
�������
System.out.println( "������
java StockClient get <stock-name>" );
�������
System.exit( 0 );
��� }
���
static void checkArgs( String[] args )
��� {
�������
if ( args.length < 2 )
�����������
usage();
�������
stock = args[1];
�������
if ( args[0].equalsIgnoreCase( "get" )) {
�����������
if ( args.length > 2 )
���������������
usage();
�����������
doGet = true;
������� }
else if ( args[0].equalsIgnoreCase( "put" )) {
�����������
if ( args.length != 3 )
���������������
usage();
������������
doGet = false;
������������
value = Integer.valueOf(args[2]);
������� }
else if ( args[0].equalsIgnoreCase( "getValue" )) {
�����������
if ( args.length != 2 )
���������������
usage();
������������
doGetValue = true;
������������
value = Integer.valueOf(args[1]);
������� }
else
�����������
usage();
��� }
���
static boolean doGet = false;
���
static boolean doGetValue = false;
���
static String stock = null;
���
static Integer value = null;
}
Compile it.
You need a reference to the HomeInterface. If compiling fails then the best
thing to do is add the EJB jar to you CLASSPATH. Now the client knows where the
HomeInterface is.
Finally
Hopefully
it worked, if not then feel free to e-mail me. Start JBoss. Then open a DOS
prompt and go to the directory of the client application. To test the EJB type:
java
StockClient put Ordina 2000000
then press
enter and type:
java
StockClient getValue 2000000
If it works:
Congratulations!
Edgar de Graaf