Novell is now a part of Micro Focus

How to Integrate NDS eDirectory, JDBC, and EJB

Articles and Tips: article

J. Jeffrey Hanson
Senior eBusiness Architect
Financial Fusion
jhanson583@aol.com

01 May 2001


Java, LDAP, JDBC, and EJB are powerful tools for building distributed applications that work across intranets, extranets, and the Internet. This article discusses how to integrate NDS eDirectory, JDBC, and EJB.

Definition and Role of Directory Services

Directory services are special purpose databases designed to assist in locating organizations, people, and other entities such as servers, printers, databases, groups, applications, etc. They link organizations and other entities together using a hierarchical tree structure and maintain logical order in a network that may interconnect many sites and may support thousands of users with multiple network objects and interconnections. Using defined standards for the tree structure allows individual organizations to decide for themselves which servers to use for their own directory services, while at the same time providing a way for each organization to access the tree for coordinated directory services. If a directory service user knows one or more attributes of objects, the user can query the directory to get a list of objects that match the attributes. Thus, a directory service allows a user to find any object, given one or more of its attributes. Directory services provide a single point of network management, allowing you to add, remove, and relocate objects and resources easily. A directory service forms a namespace in which the name of an object in the directory can be resolved to the object itself. Directory services locate network users and resources, manage them, and authenticate and secure them. A directory is a set of one or more directory trees.

Directory Trees

A directory tree describes a hierarchy of objects and containers. Endpoints on the tree are leaf objects, while other nodes in the tree are containers. A directory tree is used to show how objects are connected or the path from one object to another.

Attributes

Attributes hold data describing the subject identified by a directory object. Examples of attributes are the user's name, location, and e-mail address.

Object Classes

Object classes are logical groupings of objects such as user accounts, computers, domains or organizational units. Object classes can be thought of as templates that define the attributes an object can contain, the parent objects that can contain the object itself and the classes that make up the parental hierarchy of the class.

Schema

A directory schema defines the set of all object classes and attributes that can be stored in the directory. Through a schema, we define where an object class can be created in a directory tree by specifying the legal parents of the class. A schema can be extended when there are no existing object classes that meet the users' needs; also, new attributes can be added to the schema.

Objects

An object is an instance of a class defined in the directory schema that represents a resource, such as a user, a printer, a server, or an application.

Containers

A container is a parent object for a group of objects and other containers. For example, a department is a container that holds a group of employees. The employees are the objects, and the department is the container. An Organizational Unit is one of the most important containers in the directory. Organizational Units are used to organize objects such as computers, printers, user accounts, applications and even other Organizational Units into logical administrative groups.

Security

All objects in a directory are protected by access control lists and other rights mechanisms that determine who can see an object and what actions each user can perform on the object.

Limitations of Directory Services

Directory services lack the heavy update, transaction processing, and reporting capabilities of relational databases. Directory services typically do not offer two-phase commits, true relational structure, or a relational query language like SQL. A directory services information model is based on simple pairings of attributes and values. Thus, it's not well suited for arbitrary BLOB data that you will find managed by typical file systems. It's also not optimized for write performance and is typically unable to furnish fine-grained access to values. Finally, it doesn't typically expose the locking semantics needed to read-protect and write-protect files.

Definition and Role of Databases

Databases store multiple types of data for computer applications, and process the transactions on the data associated with computer applications. Databases collect, sort, and store data in formats that allow reporting tools to easily access the data and view it many different ways. A database structures and manipulates data stored on a computer independently of the specific machine on which the database resides. A database provides navigation for accessing data, typically using a high-level, nonprocedural language.

Limitations of Databases

Although there are several types of databases, we will restrict our discussion to object-oriented (OO) databases and relational databases. OO databases provide a better mapping between application objects and storage structures than do relational databases; however, there are some limitations and drawbacks of OO databases. These can include:

  • Limited view mechanisms

  • Limited support for data administration

  • Limited support for schema evolution

  • Poor support for integrity constraints

Relational databases provide easy access to data using standardized query mechanisms and can present multiple views of the same data to the user as needed; however, there are limitations and drawbacks of relational databases as well. These can include:

  • The structure of relational databases (tables, rows, columns) does not accommodate complex data types easily. This is sometimes referred to as impedance mismatch.

  • Complex data stored as BLOBS can be retrieved, but not searched, indexed, or manipulated.

  • A restricted set of data types even for less complex data.

  • An inadequate model of real-world objects.

  • Prohibitive cost.

Definition and Role of Enterprise JavaBeans

Enterprise JavaBeans is a component architecture for the development and deployment of object-oriented, distributed, enterprise-level applications. Applications written correctly using the Enterprise JavaBeans architecture are usually very scalable, as well as transactional, multiuser, and secure.

EJB Containers

An EJB container provides the runtime environment for enterprise beans which includes security, concurrency, lifecycle management, transaction, deployment, and other services. An EJB container resides within an EJB server.

EJB Servers

An EJB server provides services to an EJB container such as transaction management to perform two-phase commits across all the participating resources. An EJB server may host one or more EJB containers.

Entity Beans

An entity bean represents an entity of persistent data maintained in a database or other data store. An entity bean can manage its own persistence or let the EJB container handle the persistence for it. An entity bean is identified and found by a primary key. If the container in which an entity bean is hosted shuts down abnormally, the entity bean, its primary key, and all references survive and can be re-instantiated when the host is restarted.

Session Beans

A session bean is an enterprise bean that is created by a client and that usually exists only for the duration of a single client/server session or request. A session bean performs operations, such as business logic or accessing a database. A session bean may be transactional. A session bean is not recoverable should an abnormal system shutdown occur. Session beans can be either stateless or they can be stateful (maintain conversational state across requests and transactions). If they are stateful, the EJB container manages the state; however, a session bean must manage its own persistence.

Limitations of Enterprise JavaBeans

The following is a list of some limitations of EJBs:

  • Using static, non-final fields. Declare all "static" fields in your EJB as "final."

  • Thread usage.

  • Using AWT APIs for keyboard input and display output.

  • Using java.io operations for file access. EJBs should use resource managers such as JDBC to store and retrieve application data rather than the file system APIs.

  • Listening to or accepting socket connections, or using a socket for multicast. EJBs should not act as socket servers; however, EJBs can act as a socket clients or RMI clients.

  • Using the Reflection API.

  • Attempt to create or obtain a class loader.

  • Attempt to set or create a new security manager.

  • Attempt to stop the JVM.

  • Attempt to change the input, output, and error streams.

  • Setting the socket factory used by a URL object's ServerSocket, Socket, or stream handler.

  • Loading native libraries.

  • Accessing or modifying security configuration objects (Policy, Security, Provider, Signer, and Identity).

  • Passing the "this" reference as an argument or returning the "this" reference as a result. Instead, you must use the result of the getEJBObject() available in SessionContext or EntityContext.

Working in a Distributed World

The following section discusses working with Directory Services, a Database, and EJB.

Working with Directory Services

In the past few years, the introduction of Lightweight Directory Access Protocol (LDAP) has gained increasing momentum as the de facto standard for accessing directory services servers. LDAP's basic structure is based on a simple information tree metaphor called a directory information tree (DIT). Each leaf in the tree is an entry; the first or top-level entry is the root entry. An entry includes a distinguished name (DN) and any number of attribute/value pairs. The DN, which is the name of an entry, must be unique. It shows the relationship between the entry and the rest of the DIT in a manner similar to the way in which a file's full path name shows its relationship with the rest of the files in a file system. While a path to a file reads left to right, a DN, in contrast, reads from right to left.

The LDAP protocol defines six operations that can be performed: binding/authenticating to the directory, searching for entries in the directory, comparing entries against entries in the directory, adding entries to the directory, modifying existing entries, and removing an entry from the directory. Other services defined by LDAP are referral (allowing directory servers to link to each other), replication, and encryption using SASL, SSL, user certificates, and Access Control Lists. There are a variety of LDAP server products on the market today.

Working with Databases

Java Database Connectivity (JDBC) works in much the same way that Open DataBase Connectivity (ODBC) does: it provides a way for applications to interact with multiple databases using the same source code. The source code is written using the Java programming language. The java.sql package included with the Java Developer's Kit (JDK) provides the JDBC APIs. The JDBC API provides mechanisms for connecting to datasources, creating databases, creating tables, adding rows to tables, removing rows from tables, updating data, etc.

Working with EJB

EJB defines a distributed component model that removes many of the details of a distributed programming environment from the software developer. EJB provides servers and containers that handle data marshaling, transaction management, object persistence management, object life-cycle management, session management, and other necessary tasks that distributed programming entails. With these details out of the way, a software developer is free to work on the business logic for each particular service or application.

Locating, Storing, and Interacting within the Distributed World

This section discusses Novell support for LDAP, EJB, and JDBC.

LDAP Support from Novell

Novell provides easy-to-use Java components that can be used to integrate Web applications with NDS using LDAP. These components are called eCommerce LDAP Beans. Using the Model-View-Controller (MVC) and Command design patterns, the eCommerce LDAP Beans provide component-based functionality for integrating Web applications with LDAP directories. These components enable authentication, browsing, read/write access to NDS, along with context-less login, SSL security, and other features. The following examples demonstrate some common uses for these components.

Authenticating
public static LdapConnection authenticate(String url, String dn, String password)
   throws command.novell.ecb.CommandException
{ 
   // create bean
   com.novell.ecb.ldap.AuthenticateLdap bean = new
   com.novell.ecb.ldap.AuthenticateLdap();
   
   // set properties
   bean.setURL(url);
   bean.setDN(dn);
   bean.setPassword(password);
   
   // the following property is optional. Use if SSL security is desired
   bean.setProtocol("ssl"); 
   
   // execute
   bean.execute();
   
   // return connection
   return bean.getLdapConnection();
}
Un-Authenticating
public static void unauthenticate(com.novell.ecb.ldap.LdapConnection connection)
   throws command.novell.ecb.CommandException
{
   // create bean
   com.novell.ecb.ldap.UnauthenticateLdap bean = new
   com.novell.ecb.ldap.UnauthenticateLdap();

   // set properties
   bean.setLdapConnection(connection);
   
   // Execute
   bean.execute();
}
Listing Entries
public static void listEntries(com.novell.ecb.ldap.LdapConnection connection,
   String dn) throws command.novell.ecb.CommandException
{
   // create bean
   com.novell.ecb.ldap.ListLdapEntries bean = new
   com.novell.ecb.ldap.ListLdapEntries();
   
   // set properties
   bean.setLdapConnection(connection);
   bean.setDN(dn);
   
   // execute
   bean.execute();
   
   // enumerate entries
   for (javax.naming.Enumeration e = bean.getLdapEntries(); e.hasMoreElements();)
   {
      javax.naming.NameClassPair entry =
	  (javax.naming.NameClassPair)e.nextElement();
      String name = entry.getName();
   }
}
Reading Attributes of an Entry
public static void readEntry(com.novell.ecb.ldap.LdapConnection connection,
String dn) throws command.novell.ecb.CommandException
{
   // create bean
   com.novell.ecb.ldap.ReadLdapEntry bean = new com.novell.ecb.ldap.
   ReadLdapEntry();
   
   // set properties
   bean.setLdapConnection(connection);
   bean.setDN(dn);
   
   // execute
   bean.execute();
   
   // get entry
   com.novell.ecb.ldap.LdapEntry entry = bean.getLdapEntry();
   
   // get attribute set
   javax.naming.directory.Attributes attrs = entry.getAttributes();
   
   // enumerate attributes
   for (javax.naming.Enumeration e = attrs.getAll(); e.hasMoreElements(); ) {
      javax.naming.directory.Attribute attr =
	  (javax.naming.directory.Attribute)e.nextElement();
      String id = attr.getID();
   }
}
Creating an Entry
public static void createEntry(com.novell.ecb.ldap.LdapConnection connection, 
   String dn, String objectClass) 
   throws command.novell.ecb.CommandException
{
   // create bean
   com.novell.ecb.ldap.CreateLdapEntry bean =
   new com.novell.ecb.ldap.CreateLdapEntry();
   
   // create attributes
   javax.naming.directory.Attributes attrs =
   new javax.naming.directory.BasicAttributes();
   attrs.put(new javax.naming.directory.BasicAttribute("objectClass",
   objectClass));

   // set properties
   bean.setLdapConnection(connection);
   bean.setDN(dn);
   bean.setAttributes(attrs);
   
   // execute
   bean.execute();
   
   // get entry
   com.novell.ecb.ldap.LdapEntry entry = bean.getLdapEntry();
}
Adding an Attribute to an Entry
public static void modifyEntryAdd(com.novell.ecb.ldap.LdapConnection connection,
               String dn, String attrName, String attrValue)
   throws command.novell.ecb.CommandException
{
   // create bean
   com.novell.ecb.ldap.ModifyLdapEntry bean =
   new com.novell.ecb.ldap.ModifyLdapEntry();
   
   // create modifications
   com.novell.ecb.ldap.LdapModificationSet mods =
   new com.novell.ecb.ldap.LdapModificationSet();
   mods.add(javax.naming.directory.DirContext.ADD_ATTRIBUTE,
         new javax.naming.directory.BasicAttribute(attrName, attrValue));
   // set properties
   bean.setLdapConnection(connection);
   bean.setDN(dn);
   bean.setModificationSet(mods);
   
   // execute
   bean.execute();
}
Deleting an Entry
public static void deleteEntry(com.novell.ecb.ldap.LdapConnection connection,
String dn)
   throws command.novell.ecb.CommandException
{
   // create bean
   com.novell.ecb.ldap.DeleteLdapEntry bean =
   new com.novell.ecb.ldap.DeleteLdapEntry();
   
   // set properties
   bean.setLdapConnection(connection);
   bean.setDN(dn);
   
   // execute
   bean.execute();
}

EJB Support from Novell

EJB requires an environment that provides an EJB server and one or more EJB containers. Novell ships the WebSphere application server with the NetWare operating system. WebSphere provides one of the most powerful EJB environments on the market today. WebSphere enables users to define logical abstractions on physical entities such as EJBs, Java Server Pages (JSP), HTML pages, property files, images, and Java Servlets from disparate file system directories and servers. These abstractions are referred to as Web applications and Enterprise applications. With a Web application and/or an Enterprise application defined, the user can apply security policies, connection pooling functionality, load balancing rules, and other operations to the application.

JDBC Support from Novell

Novell builds and ships a version of the Java Developer Kit (JDK) and Java Runtime Environment (JRE) with the NetWare operating system. The java.sql package, defining the JDBC APIs, is included with these tools.

Putting EJB and LDAP Together

Let's define a stateless, session EJB that models a user and the user's actions regarding a particular application. The actions that the user can perform, depend on the user's position in NDS, thus, will keep some of the information about the user in the directory and the rest of the user's information in an Oracle database. The EJB will encapsulate all the needed operations on the directory using Novell's eCommerce LDAP Beans and operations on the database using JDBC. Since the directory has significantly slower update speed, we will store information about the user that seldom changes in the directory and information about the user that changes often in the database. We will depend on the connection pool of the WebSphere application server for our database connection optimizations. The following examples show our user EJB with the LDAP calls inserted.

/**
* User.java - This is the remote interface of our enterprise JavaBean, it
* defines all of our business logic.
*/
   
package ejb.user;
import java.rmi.RemoteException;
import java.rmi.Remote;
import javax.ejb.*;
   
public interface User extends EJBObject
{ 
// business-logic method declarations go here
   
   public com.novell.ecb.ldap.LdapConnection authenticate(String userName,
                                                            String password)
      throws RemoteException;

   public void unauthenticate(com.novell.ecb.ldap.LdapConnection conn)
      throws RemoteException;

   public Boolean entryExists(com.novell.ecb.ldap.LdapConnection conn,
                              String entryDN,
                              String attrName,
                              String attrValue)
      throws RemoteException;
} 
   
/**
* UserHome.java - This is the Home interface it must extend javax.ejb.EJBHome
* and define one or more create() methods for the bean.
*/
   
package ejb.user;
   
import javax.ejb.*;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.*;
   
/**
* UserHome.java - This interface is declares only one create method.
*/
public interface UserHome extends EJBHome
{
public User create()
throws CreateException, RemoteException;
   
}
   
/**
* UserBean.java -- This contains our business logic and must implement
* javax.ejb.SessionBean.
*/
   
package ejb.user;
   
import javax.ejb.*;
import java.io.Serializable;
import java.util.*;
import java.rmi.*;
   
public class UserBean implements SessionBean
{
private transient SessionContext ctx;
private transient Properties props;
   
/**
* Standard session bean methods
*/
public void ejbCreate ()
      throws RemoteException
{
}
   
public void ejbRemove()
      throws RemoteException
{
}
   
public void ejbActivate()
      throws RemoteException
{
}
   
public void ejbPassivate()
      throws RemoteException
{
}
   
public void setSessionContext(SessionContext ctx)
      throws RemoteException
{    
this.ctx = ctx;
props = ctx.getEnvironment();
}
   
/**
* Our business methods 
*/
   public com.novell.ecb.ldap.LdapConnection authenticate(String userName,
                                                            String password)
      throws RemoteException
   {
   // create command bean 
   com.novell.ecb.ldap.AuthenticateLdap bean =
   new com.novell.ecb.ldap.AuthenticateLdap();
   
   // set properties
   bean.setURL(url);
   bean.setDN(dn);
   bean.setPassword(password);
   
   // set for SSL protocol
   bean.setProtocol("ssl"); 
   
   // execute
   bean.execute();
   
   // return connection
   return bean.getLdapConnection();
   }
   
   public void unauthenticate(com.novell.ecb.ldap.LdapConnection conn)
      throws RemoteException
   {
   // create command bean 
   com.novell.ecb.ldap.UnauthenticateLdap bean =
   new com.novell.ecb.ldap.UnauthenticateLdap();
   
   // set properties
   bean.setLdapConnection(connection);
   
   // execute
   bean.execute();
   }
   
   public Boolean entryExists(com.novell.ecb.ldap.LdapConnection conn,
                              String entryDN,
                              String attrName,
                              String attrValue)
      throws RemoteException
   {
   com.novell.ecb.ldap.SearchLdapEntries bean =
   new com.novell.ecb.ldap.SearchLdapEntries();
   
   Attributes attrs = new BasicAttributes(attrName, attrValue);

   bean.setConnection(conn);
   bean.setDN(request.getParameter("DN"));
   bean.setMatchingAttributes(attrs);
   
   bean.execute();
   
      return(bean.getLdapEntries().hasMoreElements());
   }
}

/**
* UserClient.java - demonstrates using a Java application to talk to
* the UserBean
*/
   
package ejb.user;
   
import javax.ejb.*;
import javax.naming.*;
import java.rmi.*;
import java.util.Properties;
   
public class UserClient
{
static String userName = null;
static String password = null;
static String url = "iiop://myhost:900";
   static String contextFactory = "com.ibm.ejs.ns.jndi.CNInitialContextFactory";
   
/**
* Gets an initial context.
*
* @return Context
* @exception java.lang.Exception on error
*/
static public Context getInitialContext() 
throws Exception
{
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory );
p.put(Context.PROVIDER_URL, url);
return new InitialContext(p);
}
   
public static void main(String[] args)
{
parseArgs(args);
   
try {
// Get the initial context
Context ctx = getInitialContext();
   
// Lookup the home
Object userObj = ctx.lookup("UserHome");
   
// Cast the home
UserHome userhome =
            (UserHome)javax.rmi.PortableRemoteObject.narrow(
                           (org.omg.CORBA.Object)userObj, UserHome.class);
   
// Create the actual bean
User   user = userhome.create();
   
// authenticate
         com.novell.ecb.ldap.LdapConnection conn =
		 user.authenticate(userName, password);
   
// check to make sure the user exists
         Boolean exists = user.entryExists(conn,
                  "cn=John Doe,ou=myorgunit,o=myserver.com",
                  "Surname", "Doe");
   
// un-authenticate
         user.unauthenticate(conn);
} catch (Exception e) {
System.out.println("Error: " +e.toString());
e.printStackTrace();
}
}
   
static void parseArgs(String args[])
{
if ((args == null) || (args.length < 3))
return;
   
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-url"))
url = args[++i];
else if (args[i].equals("-user"))
user = args[++i];
else if (args[i].equals("-password"))
password = args[++i];
}
}
}

Our First Look at JDBC

The following examples show how JDBC can be used to connect to a database, iterate over rows in the database, add rows to the database, and then close the connection to the database. We assume a table called "USER" exists with columns FULLNAME and USERID.

import java.sql.*;
   
class User
{
public static void main (String args [])
throws SQLException
{
//=================================================
// Load driver and establish a connection
//=================================================
   
// Load the JDBC driver
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
   
// Connect to the database
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@myhost:1521:orcl", "username", "password");
   
//=================================================
// Iterate over names in the USER table
//=================================================
   
// Create a Statement
Statement stmt = conn.createStatement ();
   
// Select the USERID column from the USER table
ResultSet rset = stmt.executeQuery("select USERID from USER");
   
// Iterate through the result and print the user IDs
while (rset.next ())
System.out.println(rset.getString(1));
   
// Close the ResultSet
rset.close();
   
// Close the Statement
stmt.close();
   
//=================================================
// Insert new names in the USER table
//=================================================
   
PreparedStatement pstmt = 
conn.prepareStatement("insert into USER (FULLNAME, USERID) values (?, ?)");
   
// Add John Doe as a user
pstmt.setInt (1, "John Doe");   // The first ? represents FULLNAME
pstmt.setString (2, "jdoe");    // The second ? represents USERID
   
// Do the insertion
pstmt.execute ();
   
// Close the statement
pstmt.close();
   
//=================================================
// Close the connection
//=================================================
   
conn.close();   
}
}

Putting EJB, LDAP, and JDBC Together

/**
* User.java - We add our database calls here.
*/
   
package ejb.user;
   
import java.rmi.RemoteException;
import java.rmi.Remote;
import javax.ejb.*;
   
public interface User extends EJBObject
{ 
   // business-logic method declarations go here
   
   public com.novell.ecb.ldap.LdapConnection authenticate(String userName,
                                                            String password)
      throws RemoteException;
   
   public void unauthenticate(com.novell.ecb.ldap.LdapConnection conn)
      throws RemoteException;
   
   public Boolean entryExists(com.novell.ecb.ldap.LdapConnection conn,
                              String entryDN,
                              String attrName,
                              String attrValue)
      throws RemoteException;
   
   public void addEntryToDB(String fullName, String userID, String address)
      throws RemoteException;
   
   public String getAddressFromDB(String fullName, String userID)
      throws RemoteException;
} 
   
/**
* UserBean.java -- We add our database code here.
*/
   
package ejb.user;
   
import javax.ejb.*;
import java.io.Serializable;
import java.util.*;
import java.rmi.*;
import java.sql.*;
   
public class UserBean implements SessionBean
{
private transient SessionContext ctx;
private transient Properties props;
   
/**
* Standard session bean methods
*/
public void ejbCreate ()
      throws RemoteException
{
}
   
public void ejbRemove()
      throws RemoteException
{
}
   
public void ejbActivate()
      throws RemoteException
{
}
   
public void ejbPassivate()
      throws RemoteException
{
}
   
public void setSessionContext(SessionContext ctx)
      throws RemoteException
{    
this.ctx = ctx;
props = ctx.getEnvironment();
}
   
/**
* Our business methods 
*/
   public com.novell.ecb.ldap.LdapConnection authenticate(String userName,
                                                            String password)
      throws RemoteException
   {
   // create command bean 
   com.novell.ecb.ldap.AuthenticateLdap bean =
   new com.novell.ecb.ldap.AuthenticateLdap();
   
   // set properties
   bean.setURL(url);
   bean.setDN(dn);
   bean.setPassword(password);
   
   // set for SSL protocol
   bean.setProtocol("ssl"); 
   
   // execute
   bean.execute();
   
   // return connection
   return bean.getLdapConnection();
   }
   
   public void unauthenticate(com.novell.ecb.ldap.LdapConnection conn)
      throws RemoteException
   {
   // create command bean 
   com.novell.ecb.ldap.UnauthenticateLdap bean =
   new com.novell.ecb.ldap.UnauthenticateLdap();
   
   // set properties
   bean.setLdapConnection(connection);
   
   // execute
   bean.execute();
   }
   
   public Boolean entryExists(com.novell.ecb.ldap.LdapConnection conn,
                              String entryDN,
                              String attrName,
                              String attrValue)
      throws RemoteException
   {
   com.novell.ecb.ldap.SearchLdapEntries bean =
   new com.novell.ecb.ldap.SearchLdapEntries();
   
   Attributes attrs = new BasicAttributes(attrName, attrValue);
   
   bean.setConnection(conn);
   bean.setDN(request.getParameter("DN"));
   bean.setMatchingAttributes(attrs);
   
   bean.execute();
   
      return(bean.getLdapEntries().hasMoreElements());
   }
   
   
   public void addEntryToDB(String fullName, String userID, String address)
      throws RemoteException
   {
   InitialContext jndiContext = new InitialContext();
   DataSource source = (DataSource)jndiContext.lookup("java:comp/env/jdbc/USER");
   Connection conn = source.getConnection(); }
   
   PreparedStatement pstmt = 
   conn.prepareStatement("insert into USER (FULLNAME, USERID) values (?, ?, ?)");
   
   // Add the user
   pstmt.setInt(1, fullName);      // The first ? represents FULLNAME
   pstmt.setString(2, userID);   // The second ? represents USERID
   pstmt.setString(3, address);   // The third ? represents ADDRESS
   
   // Do the insertion
   pstmt.execute ();
   
   // Close the statement
   pstmt.close();
   
   // Close the connection
   conn.close();   
   }
   
   public String getAddressFromDB(String fullName, String userID)
      throws RemoteException
   {
      String address = "";
   
   InitialContext jndiContext = new InitialContext();
   DataSource source = (DataSource)jndiContext.lookup("java:comp/env/jdbc/USER");
   Connection conn = source.getConnection(); }
   
   // Create a Statement
   Statement stmt = conn.createStatement();
   
   // Select the USERID column from the USER table
   ResultSet rset = stmt.executeQuery("select ADDRESS from USER where
                     FULLNAME = " +fullName +" AND USERID = " +userID);
   
   // Get the address
   if (rset.next())
   address = rset.getString(1);
   
   // Close the ResultSet
   rset.close();
   
   // Close the Statement
   stmt.close();
   
   // Close the connection
   conn.close();
   
      return(address);  
   }
}
   
/**
* UserClient.java - We use the added database calls here
*/
   
package ejb.user;
   
import javax.ejb.*;
import javax.naming.*;
import java.rmi.*;
import java.util.Properties;
   
public class UserClient
{
static String userName = null;
static String password = null;
static String url = "iiop://myhost:900";
   static String contextFactory = "com.ibm.ejs.ns.jndi.CNInitialContextFactory";
   
/**
* Gets an initial context.
*
* @return Context
* @exception java.lang.Exception on error
*/
static public Context getInitialContext() 
throws Exception
{
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory );
p.put(Context.PROVIDER_URL, url);
return new InitialContext(p);
}
   
public static void main(String[] args)
{
parseArgs(args);
   
try {
// Get the initial context
Context ctx = getInitialContext();
   
// Lookup the home
Object userObj = ctx.lookup("UserHome");
   
// Cast the home
UserHome userhome =
            (UserHome)javax.rmi.PortableRemoteObject.narrow(
                           (org.omg.CORBA.Object)userObj, UserHome.class);

// Create the actual bean
User   user = userhome.create();
   
// authenticate
         com.novell.ecb.ldap.LdapConnection conn =
		 user.authenticate(userName, password);
   
// check to make sure the user exists
         Boolean exists = user.entryExists(conn,
                  "cn=John Doe,ou=myorgunit,o=myserver.com",
                  "Surname", "Doe");
   
   // add user if needed
         if (!exists) {
            user.addEntryToDB("John Doe", "jdoe", "123 anywhere st.");
         }
         
   // retrieve address just for kicks
         String address = user.getAddressFromDB("John Doe", "jdoe");
         System.out.println("Address: " +address );
   
   // un-authenticate
         user.unauthenticate(conn);
} catch (Exception e) {
System.out.println("Error: " +e.toString());
e.printStackTrace();
}
}
   
static void parseArgs(String args[])
{
if ((args == null) || (args.length < 3))
return;
   
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-url"))
url = args[++i];
else if (args[i].equals("-user"))
user = args[++i];
else if (args[i].equals("-password"))
password = args[++i];
}
}
}

Summary

Java, LDAP, JDBC, and EJB aReferencesre powerful tools for building distributed applications that work across intranets, extranets, and the Internet. Using these tools, developers can write applications that address data storage, data security, object lookup, authentication, and transaction management without regard to operating systems or programming language differences. We can employ NDS eDirectory to model our world by using LDAP and by using databases to store and retrieve dynamic data via JDBC, and we can write powerful, distributed applications using EJB.

References

* Originally published in Novell AppNotes


Disclaimer

The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.

© Copyright Micro Focus or one of its affiliates