Java Tutorial - Java Scipt : The Remote Interface

Java Tutorial - Java Scipt :

The Remote Interface


The code remote interface is shown below. It exposes the methods of the EJB for access by the client:
package com.oldfriends.session;

import com.oldfriends.user.UserDTO;
import java.rmi.RemoteException;
import javax.ejb.*;
public interface UserSessionRemote extends javax.ejb.EJBObject
{
public String getHello()
throws RemoteException, EJBException;
public UserDTO getUserByUserid( String userid )
throws RemoteException, EJBException;
public UserDTO getUserByLogin( String login)
throws RemoteException, EJBException;
public UserDTO getUserByEmail( String login)
throws RemoteException, EJBException;
public UserDTO addUser( UserDTO user )
throws RemoteException, EJBException;
public void updateUser( UserDTO user )
throws RemoteException, EJBException;
public UserDTO[] getUsersByYear( int year )
throws RemoteException, EJBException;
public UserDTO[] getAllUsers()
throws RemoteException, EJBException;

Java Tutorial - Java Scipt : The Home Interface

Java Tutorial - Java Scipt :

The Home Interface


The following code is the home interface for our session bean. This will be used to create and return an instance of the remote interface to the client: package com.oldfriends.session;

import com.oldfriends.session.UserSessionRemote;
import java.rmi.RemoteException;
import javax.ejb.*;
public interface UserSessionHome extends EJBHome
{
UserSessionRemote create() throws RemoteException, CreateException;
}
The only method we add here is the create method.

Java Tutorial - Java Scipt : Locating Resources

Java Tutorial - Java Scipt :

Locating Resources


The ResourceLocator class provides a place to put the code that is used to look up resources in the system. Often resources only need to be looked up once and can be cached for subsequent uses. The ResourceLocator is designed so it can be used by many classes, and it caches the things that it can cache. The source code for the ResourceLocator is provided below: package com.oldfriends.utils;

import java.sql.*;
import javax.ejb.*;
import javax.naming.*;
import javax.rmi.PortableRemoteObject;
import javax.sql.DataSource;
public class ResourceLocator
{
private static Context ctx;
private static DataSource datasource;
private static final String DSNAME = “MySqlDS”;
public static Context getInitialContext()
throws NamingException, ClassCastException
{
Context myctx;
if( ResourceLocator.ctx == null )
{
myctx = new InitialContext();
ResourceLocator.ctx = myctx;
}
else
myctx = ResourceLocator.ctx;
return myctx;
}
public static EJBHome getLocalHomeInterface(String jndiName)
throws NamingException, ClassCastException
{
Context myctx = ResourceLocator.getInitialContext();
EJBHome home = (EJBHome)myctx.lookup(jndiName);
return home;
}
public static EJBHome getHomeInterface(
String jndiName, Class theHomeClass )
throws NamingException, ClassCastException
{
EJBHome home;
Context myctx = ResourceLocator.getInitialContext();
Object obj = myctx.lookup(jndiName);
home = (EJBHome)PortableRemoteObject.narrow( obj, theHomeClass );
return home;
}
public static DataSource getDataSource( String jndiName )
throws NamingException
{
DataSource ds = null;
if( ResourceLocator.ctx == null )
{
ResourceLocator.ctx = new InitialContext();
}
ds = (DataSource)ResourceLocator.ctx.lookup(jndiName);
return ds;
}
public static Connection getConnection()
throws NamingException, SQLException
{
Connection conn;
if(datasource==null)
{
datasource = ResourceLocator
.getDataSource(ResourceLocator.DSNAME);
}
conn = datasource.getConnection();
return conn;
}
}

The ResourceLocator shown here is a very simple, almost minimalist, one. It provides methods to:

·         Retrieve and cache the initial context
·         Look up and convert LocalHome interfaces
·         Look up and convert home interfaces
·         Look up and cache DataSources
·         Get DataBase connections

Using a ResourceLocator often provides for more efficient access to resources and minimizes the knowledge needed to access the resources in various classes. Use of a ResourceLocator is considered to be a J2EE best practice.

Java Tutorial - Java Scipt : Creating a Session Façade

Java Tutorial - Java Scipt :

Creating a Session Façade


The session facade is a primary design pattern for enterprise Java development. In general, the facade pattern presents a simpler interface to a complex set of underlying interfaces. The session facade can improve performance in distributed systems. Facades are normally course grained; for example, instead of making many small network round trips to read each field of an entity bean a session facade bundles the fields up into a value bean or DTO for single network transfer. The facade can also represent a single entry point for accessing all of the data related to a particular domain object. In our case, all of the information that can be tied to a user record can be made accessible via the facade. As the underlying application becomes more complex, the facade can remain fairly simple from the client’s perspective. The facade also acts as an adapter layer between the client programs and the underlying business components. As the underlying infrastructure changes the clients are only dependent on the facade remaining the same. Our facade is a stateless session bean that accesses and uses the entity bean we have just created to provide clients with access to the information about users. This information is not necessarily limited to data in the user table. As the system is expanded, we should be able to use this session bean to retrieve information that is stored throughout the database. Following is the source code for our session bean: package com.oldfriends.session;

import com.oldfriends.entity.UserLocal;
import com.oldfriends.entity.UserLocalHome;
import com.oldfriends.user.UserDTO;
import com.oldfriends.utils.*;
import java.lang.ClassCastException;
import javax.ejb.*;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
public class UserSessionEJB implements javax.ejb.SessionBean
{
protected UserLocalHome userHome = null;
protected SessionContext sessionCtx = null;
public UserSessionEJB() throws EJBException
{
}
public String getHello() throws EJBException
{
return “Hello from UserSessionEJB”;
}
public UserDTO getUserByUserid(String uid)
throws EJBException
{
UserLocal lu;
UserDTO user;
try
{
UserLocalHome lh = lookupUserLocalHome();
lu = lh.findByPrimaryKey(uid);
return buildUserBean( lu );
}
catch(FinderException fe )
{
throw new EJBException( “getUser: Could not findkey(“+uid+”)”,fe);
}
catch(Exception e)
{
throw new EJBException( “getUserByUserid: UID=”+uid ,e);
}
// return buildUserBean( lu );
}
public UserDTO getUserByLogin( String login )
throws EJBException
{
UserLocal lu;
try
{
UserLocalHome lh = lookupUserLocalHome();
lu = lh.findByLoginId(login);
}
catch(FinderException fe )
{
throw new EJBException( “getUser: Could not findkey(“
+ login
+ “)”,fe);
}
return buildUserBean( lu );
}
public UserDTO getUserByEmail( String email )
throws EJBException
{
UserLocal lu;
try
{
UserLocalHome lh = lookupUserLocalHome();
lu = lh.findByEmail(email);
}
catch(FinderException fe )
{
throw new EJBException( “getUser: Could not findkey(“
+ email
+ “)”,fe);
}
return buildUserBean( lu );
}
private UserDTO buildUserBean( UserLocal lu )
{
UserDTO u = new UserDTO();
u.setFirstName(lu.getFirstName());
u.setLastName(lu.getLastName());
u.setMi(lu.getMi());
u.setMaidenName(lu.getMaidenName());
u.setGradYear(lu.getGradYear());
u.setLoginId(lu.getLoginId());
u.setPassword(lu.getPassword());
u.setEmail(lu.getEmail());
u.setUserid(lu.getUserid());
return u;
}
public void updateUser( UserDTO user )
{
UserLocal lu;
try
{
UserLocalHome lh = lookupUserLocalHome();
lu = lh.findByPrimaryKey(user.getUserid());
setUser( user, lu );
}
catch(FinderException fe )
{
throw new EJBException(
“setUser: Could not findkey(“+user.getUserid()+”)”,fe);
}
catch( Exception ex )
{
throw new EJBException(
“updateUser: Unexpected Exception “,ex);
}
}
public UserDTO addUser( UserDTO user )
{
UserLocal lu;
try
{
UserLocalHome lh = lookupUserLocalHome();
lu = lh.create(user);
}
catch(CreateException cx )
{
throw new EJBException(
“addUser: could not create user”, cx);
}
return buildUserBean( lu );
}
private void setUser( UserDTO u, UserLocal lu)
throws EJBException
{
lu.setFirstName(u.getFirstName());
lu.setLastName(u.getLastName());
lu.setMi(lu.getMi());
lu.setMaidenName(u.getMaidenName());
lu.setGradYear(u.getGradYear());
lu.setLoginId(u.getLoginId());
lu.setPassword(u.getPassword());
lu.setEmail(u.getEmail());
}
private UserLocalHome lookupUserLocalHome()
throws EJBException
{
UserLocalHome home;
if( userHome != null)
return userHome;
try
{
Context ctx = ResourceLocator.getInitialContext();
home = (UserLocalHome)ctx.lookup(“ejb/LocalUserEJB”);
userHome = home;
}
catch( NamingException ne )
{
throw(
new EJBException(“UserSessionBean: Problem finding User EJB”, ne)
);
}
catch( ClassCastException cce )
{
throw(new EJBException(“UserSessionBean: Class Cast Fail”, cce));
}
catch( Exception cce )
{
throw new EJBException(
“lookupUserLocalHome: unexpected exception:”, cce);
}
return home;
}
public UserDTO[] getUsersByYear( int year )
throws EJBException
{
return null;
}
public UserDTO[] getAllUsers()
throws EJBException
{
return null;
}
public void ejbCreate()
{
}
public void ejbActivate()
throws javax.ejb.EJBException, java.rmi.RemoteException
{
}
public void ejbPassivate()
throws javax.ejb.EJBException, java.rmi.RemoteException
{
}
public void ejbRemove()
throws javax.ejb.EJBException, java.rmi.RemoteException
{
}
public void setSessionContext(SessionContext sc)
throws javax.ejb.EJBException, java.rmi.RemoteException
{
sessionCtx = sc;
}
}

This should be placed in the com.oldfriends.session directory of our project. The first interesting method here is getHello(). getHello() is used here as an aid to troubleshooting. This method should always work unless there is something wrong with your deployment. There are several private methods here that perform useful work for the bean. The private setUser() method sets the fields of a UserEJB entity bean from a User DTO object. The buildUserBean method does the opposite: it builds the UserDTO based on the contents of a UserEJB instance. The lookup UserLocalHome() method does a context lookup once and then stores the home interface for subsequent use. It uses a utility class to provide it with the InitialContext. We will look at this class after the current discussion.
The three methods are


·         getUserByUserid
·         getUserByLogin
·         getUserByEmail

These methods are all used to retrieve individual records from the user table. The record is copied into a UserDTO instance and returned to the client. The attributes of this UserDTO object can be modified, and then the object can be sent to the update user method, which retrieves the matching user record and updates it in the database. The addUser method accepts a UserDTO object and creates a new record in the database. The method returns the new record, which makes the primary key available to the client. Two methods are provided to return arrays of UserDTO objects. The first, getUsersByYear() returns an array of all of the users that share the same graduating class as passed as an argument. This method does not use the user entity bean. Instead, it performs a query directly against the MySql DataSource and converts the records in the resulting recordset to an array of UserDTO objects. This array of object is returned. getAllUsers is similar, except that it returns the entire user table as an array of UserDTO objects. The reason for doing direct queries is that for this type of data the direct query is normally more efficient than a set of individual queries on the entity beans. The rest of the methods are standard EJB life-cycle methods.

Java Tutorial - Java Scipt : Testing the Bean

Java Tutorial - Java Scipt :

Testing the Bean


Now that we have built and deployed our bean, we want to test it. This was the reason for providing home and remote interfaces for the entity bean. To test the bean, we will create a very small command line-based client. An EJB client in general needs to:

1. Get an InitialContext
2. Use the context to lookup the home interface
3. Get a remote interface from the home interface
4. Execute the methods on the remote interface

The code for the test client follows:

import javax.naming.*;
import javax.rmi.PortableRemoteObject;
import javax.ejb.DuplicateKeyException;
import com.oldfriends.entity.UserRemoteHome;
import com.oldfriends.entity.UserRemote;
import com.oldfriends.user.UserDTO;
import java.lang.ClassCastException;
import javax.ejb.EJBHome;
import javax.naming.NamingException;
public class TestUserEJB
{
private EJBHome getHomeInterface(
String jndiName, Class theHomeClass )
throws NamingException, ClassCastException
{
Context myctx = null;
EJBHome home = null;
try{
myctx = new InitialContext();
Object obj = myctx.lookup(jndiName);
home = (EJBHome)PortableRemoteObject.narrow( obj, theHomeClass );
}
catch( Exception e )
{
e.printStackTrace();
}
return home;
}
public void userEntityTest()
{
try
{
System.out.println( “Getting Home Interface”);
UserRemoteHome home = (UserRemoteHome)
getHomeInterface( “ejb/UserEJB”,
com.oldfriends.entity.UserRemoteHome.class);
System.out.println( “\nRetrieving Records”);
System.out.println( “\nFindByPrimaryKey”);
UserRemote ur =
home.findByPrimaryKey(“0000000-000000-00000000-0-00000000-1”);
System.out.println( “Name:”+
ur.getFirstName() + “ “ +
ur.getLastName()+” “+ur.getUserid());
System.out.println( “\nFindByEmail”);
ur = home.findByEmail(“janedoe@someaddr.org”);
System.out.println( “Name:”+
ur.getFirstName() + “ “ +
ur.getLastName()+” “+ur.getUserid());
System.out.println(“\nFindByLoginId”);
ur = home.findByLoginId(“jsmith”);
System.out.println( “Name:”+
ur.getFirstName() + “ “ +
ur.getLastName()+” “+ur.getUserid());
System.out.println( “\nCreating Record”);
ur = home.create(
“first”,
“last”,
“x”,
“”,
2003,
“login”,
“email”,
“password”);
System.out.println( “\nNew user=”+ur.getUserid());
System.out.print( “\nDone “);
}
catch (Exception ex)
{
System.err.println(“Caught an unexpected exception!”);
ex.printStackTrace();
}
finally
{
System.out.println( “Finally”);
}
}
public static void main(String[] args)
{
UserClient uc = new UserClient();
uc.userEntityTest();
}
}

The private getHomeInterface method is used to get the InitialContext and perform the lookup and type conversion for retrieving the home interface from JNDI. The rest of the program performs various lookups on the test data
we inserted when we created the database and then adds a new record to the table. You can use Ant to run the program. The following Ant task configures the classpath and runs the program:

<target depends=”compile” name=”run-test”>
<java classname=”TestUserEJB” dir=”.” fork=”true”>
<classpath>
<pathelement location=”.”/>
<path refid=”oldfriends.classpath”/>
</classpath>
</java>
</target>

To execute the program using Ant, enter the following command on the command line:
ant run-test The output should look something like the text shown below:
Buildfile: build.xml init: compile: run-test:
[java] Getting Home Interface
[java] Retrieving Records
[java] FindByPrimaryKey
[java] Name:John Doe 0000000-000000-00000000-0-00000000-1
[java] FindByEmail
[java] Name:Jane Doe 0000000-000000-00000000-0-00000000-2
[java] FindByLoginId
[java] Name:Jack Smith 0000000-000000-00000000-0-00000000-3
[java] Creating Record
[java] New user=5c4o042-zbp0i6-ddzhbn2w-1-ddzip0ay-6
[java] Done Finally
BUILD SUCCESSFUL
Total time: 3 seconds
Notice that the new user has a GUID automatically generated for the primary key. Now that we know we have a working entity bean, we are ready to wrap it with a session bean. The session bean is what servlets and other clients will access to retrieve data from the database.

Java Tutorial - Java Scipt : Compiling the Bean

Java Tutorial - Java Scipt :

Compiling the Bean


We will use Ant to compile the bean. Ant uses a file named build.xml to describe how to build a project. In this section, we will cover the build.xml file needed to compile our code, construct the .jar file, and deploy the .jar file
to JBoss. This build file is based on Ant version 1.5. Following are the first two lines of this file:

<?xml version=”1.0” encoding=”UTF-8”?>
<project basedir=”.” default=”compile” name=”oldfriends”>
Each Ant build file must start with a project. The project attributes define the base directory for the project, the default target for the project, and the project name. The base directory is used as the relative directory for all directory accesses. The default target will be executed if no other target is requested on the command line. The name serves as the project name and is available as a reference through the build file. Ant provides the ability to set properties that can used throughout the file. These can also be stored in a properties file, as is shown in Chapter 10.
<property name=”app.name” value=”oldfriends”/>
<property name=”jar.name” value=”user-cmp”/
<property name=”jboss.home” value=”C:/jboss-3.0.6_tomcat-4.1.18”/>
<property name=”jboss.deploy”
value=”${jboss.home}/server/default/deploy”/>
<property name=”lib.dir” value=”${jboss.home}/client”/>

These lines should be edited to reflect the values needed for your system. You can replace these parameters with their values by using the ${parameter_ name} notation within the attributes of any tag. Ant provides a very useful capability to build classpaths. The next lines build a classpath that includes every .jar file in the client subdirectory of the JBoss distribution.

<path id=”oldfriends.classpath”>
<fileset dir=”${lib.dir}”>
<include name=”*.jar”/>
</fileset>
</path>

The next line is the first target in the build file. Atarget is something that Ant will try to build. This target is the “init” target and is designed to handle any initialization that might be needed. It doesn’t do anything yet, but is provided as a placeholder to meet future needs.

<target name=”init”/>
The next target, shown here, has the responsibility for compiling our code:
<target depends=”init” name=”compile”>
<javac classpathref=”oldfriends.classpath”
debug=”true”
deprecation=”true”
destdir=”.”
srcdir=”.”>
</javac>
</target>

The target invokes the Java compiler by using the javac task. A task is something that Ant knows how to do. Ant has a number of predefined tasks, and new tasks can be added by writing Java code for Ant. The javac task uses the previously defined classpath by including a classpathref attribute. The destdir and srcdir attributes provide the option to compile the code in one directory and send the class files to a different directory. The other attributes correspond to compiler command-line arguments. This target depends on the init target. This means that Ant will not execute this target until after the init target is up to date. The next target, shown in the following code, builds the .jar file:

<target depends=”compile” name=”jar”>
<jar jarfile=”${jar.name}.jar” update=”no”>
<fileset dir=”.”>
<include name=”**/*.class”/>
</fileset>
<metainf dir=”etc”/>
</jar>
</target>

The .jar task will run the .jar utility and copy all of the files described in the fileset to the .jar file. The metainf element within the .jar task copies the files in the /etc directory into the META-INF directory of the .jar file.

 If we try to name the source directory for the meta-inf file meta-inf, the task copies the files into the .jar directory meta-inf/meta-inf. This is incorrect. and the best workaround is not to name the directory meta-inf.
Therefore, we call our directory /etc.

This is how our ejb-jar.xml, jboss.xml, and jbosscmp-jdbc.xml files are moved to the correct directory within the .jar file. The next two targets, shown here, provide a convenient means to deploy the .jar file to JBoss or to undeploy it.

<target depends=”jar” name=”deploy”>
<copy file=”${jar.name}.jar” todir=”${jboss.deploy}”/>
</target>
<target depends=”” name=”undeploy”>
<delete file=”${jboss.deploy}/${jar.name}.jar”/>
</target>

The deploy target depends on the jar target, which in turn depends on the compile target. In this way, Ant automatically rebuilds anything that is needed before deploying the .jar file. One very nice feature of JBoss is that you can start the deployment process simply by copying the .jar file into the proper deployment directory. Likewise,
you can simply delete the file to undeploy it. We defined the deployment directory as the default directory earlier in the parameter section of the build.xml file.The next target is a useful utility for removing all of the compiled files.
<target depends=”init”
description=”Clean all build products.” name=”clean”>
<delete>
<fileset dir=”.”>
<include name=”**/*.class”/>
</fileset>
</delete>
<delete file=”${jar.name}.jar”/>
<delete dir=”apidoc”/>
</target>
</project >

We close the XML file by providing the project end tag. You can run the file using the command:
ant deploy If you are successful, the output should look something like the following:
Buildfile: build.xml
init:
compile:
[javac] Compiling 16 source files to C:\mysrc\chapter13
jar:
[jar] Building jar: C:\mysrc\chapter13\user-cmp.jar
deploy:
[copy] Copying 1 file to C:\jboss-3.0.6_tomcat-4.1.18\server\
default\deploy
BUILD SUCCESSFUL
Total time: 5 seconds
If JBoss is running, the output in the JBoss console when you deploy the bean should be something similar to the following:
00:38:29,403 INFO [EjbModule] Creating
00:38:29,433 INFO [EjbModule] Deploying UserEJB
00:38:29,503 INFO [EjbModule] Created
00:38:29,503 INFO [EjbModule] Starting
00:38:29,753 INFO [EjbModule] Started
00:38:29,753 INFO [MainDeployer] Deployed package:
file:/C:/openjava/jboss-3.0.6_tomcat-4.1.18/server/default/deploy/usercmp. jar