1. 1
Copyright 2000 SyncTank Solutions, Inc.
JNDI, It’s All in the
Context
Russell Castagnaro
Chief Mentor
4Charity.com
russell@4charity.com
Copyright 2000 SyncTank Solutions, Inc.
Introduction
• Presenter
– Russell Castagnaro
– Chief Mentor
• 4Charity.com
• SyncTank Solutions, Inc
– russell@4charity.com
– Experience
2. 2
Copyright 2000 SyncTank Solutions, Inc.
Introduction
• 4Charity.com
– Application Service Provider for the Non-
Profit industry
– Pure Java development
– Http://www.4charity.com
– Locations:
• San Francisco,CA
• Honolulu, HI
– We’re Hiring…
Copyright 2000 SyncTank Solutions, Inc.
Why JNDI?
You can:
• Develop networked application.
• Find remote objects.
• Interface with distributed systems.
• Interact with non-Java, networked
systems
3. 3
Copyright 2000 SyncTank Solutions, Inc.
Presentation Goals
• Review of basic JNDI.
• Using JNDI for local service resolution.
• JNDI as an alternative to static
constants.
• Using Custom Contexts with JNDI.
• Implementing Singletons.
• Using RMI and IIOP.
• Using Events in JNDI.
Copyright 2000 SyncTank Solutions, Inc.
Who needs JNDI?
• If you want to use J2EE, you need
JNDI.
• JNDI is the standard way to access
distributed and local resources for
enterprise applications.
4. 4
Copyright 2000 SyncTank Solutions, Inc.
What is JNDI?
• JNDI is a set of interfaces.
• Provides a programming interface,
allowing for Discovery and Registration.
• Standards-based approach, providing
common API to a searchable structure of
objects.
• Naming Services
• Directory Services
Copyright 2000 SyncTank Solutions, Inc.
What is a Naming Service?
• Provides the ability to map a name or
identifier to objects or services.
• A tree-like structure, nodes can be
associated with other nodes or objects.
• Objects are bound into the JNDI tree.
• Objects can be resolved by performing
a lookup using the composite name.
5. 5
Copyright 2000 SyncTank Solutions, Inc.
Naming
JNDI Tree lives in the
Server as a collection of
Named Object References
Object/
Service
Reference
Copyright 2000 SyncTank Solutions, Inc.
What is a Directory Service?
• Provides a structure containing objects.
• Allows access to object attributes.
• Enables searching the structure using
these attributes.
• Think of a computer’s file system or an
SQL database.
• Simple JNDI has one attribute, the
object’s name.
6. 6
Copyright 2000 SyncTank Solutions, Inc.
JNDI is Like a Database
• Start with a database instance.
• Use a tablespace or ownership area.
• Access a table in the tablespace.
• Access a row in the table.
• Access a column in the row.
sqlplus scott@beq-local
“SELECT name FROM scott.emp;”
Copyright 2000 SyncTank Solutions, Inc.
JNDI is Like a File System
• Start with a mounted drive.
• Use a subdirectory.
• Access a subdirectory.
• Access a file.
“C:/data/your_client/financials.xls”
7. 7
Copyright 2000 SyncTank Solutions, Inc.
Using JNDI
• Start with an Initial Context.
• Navigate to a Sub-Context.
• Drill-down through other sub-contexts.
• Access the object or service.
new InitialContext().lookup(“name”);
Copyright 2000 SyncTank Solutions, Inc.
Comparisons
JNDI File System RDBMS
Initial Context Mount Point (c:)
Database
instance
SubContext Subdirectory Tablespace
SubContext Subdirectory Table
Object File Data (row)
rmi://myserver:8080
/myobjects.example
.object
c:datayour_clie
ntfinancials.xls
SELECT *
FROM
Demo.Employee
8. 8
Copyright 2000 SyncTank Solutions, Inc.
JNDI Example
package com.synctank.labs.jndi;
import javax.naming.*;
public class TestJNDI {
public static void main(String _arg[]){
Object o = null; InitialContext ctx= null;
try{
ctx = new InitialContext(System.getProperties());
o = ctx.lookup("myobjects.example.object");
String s = (String)o; System.out.println("Found a string: "+s);
} catch (ClassCastException e) {
System.out.println("Found a "+o.getClass().getName() +": "+o.toString() );
} catch (NamingException ne) {
System.out.println("We have a problem!"); ne.printStackTrace();
} finally {
try { ctx.close(); }catch (Exception e ) {}
}
} }
Copyright 2000 SyncTank Solutions, Inc.
JNDI Example
• Primary classes are located in the
javax.naming package.
• Primarily use Context objects:
– javax.naming.Context
– javax.naming.InitialContext
– javax.naming.directory.InitialDirContext
– javax.naming.ldap.InitialLdapContext
• Use a context that matches your needs.
9. 9
Copyright 2000 SyncTank Solutions, Inc.
JNDI Providers
• JNDI Providers are the services that will be
accessed.
• More on the Service Provider Interface Later.
• Most application servers come with some
Naming service.
• J2SDK v. 1.3 includes code for many
interfaces.
• Many are downloadable, for free, at
http://java.sun.com/products/jndi/serviceproviders.html#12
Copyright 2000 SyncTank Solutions, Inc.
Starting the Service
• FS service doesn’t need to be started!
• RMI Registry (JNDI Service)
– start rmiregistry.exe OR
– java.rmi.registry.LocateRegistry.createRegistry(port);
• Weblogic JNDI service
– start startWebLogic.cmd OR
– ./startWebLogic.sh &
10. 10
Copyright 2000 SyncTank Solutions, Inc.
Getting the Initial Context
• Similar to JDBC. Use a Hashtable object.
• Two required properties:
– Context.INITIAL_CONTEXT_FACTORY
– Context.PROVIDER_URL
• Other optional properties:
– Context.SECURITY_PRINCIPAL
– Context.SECURITY_CREDENTIALS
– And many, many more..
Copyright 2000 SyncTank Solutions, Inc.
Getting the Initial Context
• Context.INITIAL_CONTEXT_FACTORY
– Actually “java.naming.factory.initial”
– Name of the Factory that creates Initial Contexts.
• Context.PROVIDER_URL
– Actually “java.naming.provider.url”
– Tells JNDI where to find the service.
• Context.SECURITY_PRINCIPAL
– Who is the connecting?
• Context.SECURITY_CREDENTIALS
– What is authentication object (password, certificate,..)
11. 11
Copyright 2000 SyncTank Solutions, Inc.
Getting the Initial Context
• Place the correct properties in a
Hashtable or Properties object.
• Call the constructor for the InitialContext
class, pass the Hashtable as a
parameter.
• Catch (throw) any Naming Exceptions!
• Remember to close() the context when
done.
Copyright 2000 SyncTank Solutions, Inc.
Getting the Initial Context
public static InitialContext getInitialContext() throws NamingException {
// use the factory and url supported by your provider
String factory = "weblogic.jndi.WLInitialContextFactory";
String url = "t3://localhost:7001"; // “http://localhost:7001”;
String user = null; String password = null;
java.util.Hashtable p = new java.util.Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, factory);
p.put(Context.PROVIDER_URL, url);
if (user != null && password != null ) {
p.put(Context.SECURITY_PRINCIPAL, user);
p.put(Context.SECURITY_CREDENTIALS, password);
}
return new InitialContext(p);
}
12. 12
Copyright 2000 SyncTank Solutions, Inc.
Getting the Initial Context
(file system)
public static void main(String[] args) {
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
String root = "file:/jdk1.3";
if (args != null && args.length > 0) root = args[0];
env.put(Context.PROVIDER_URL, "file:/jdk1.3");
try {
Context ctx = new InitialContext(env); String start = "";
if (args != null && args.length > 0) start = args[0];
listBindings(ctx,start);
ctx.close();
} catch (NamingException e) {
System.out.println("List Bindings failed: " + e);
}
}
Copyright 2000 SyncTank Solutions, Inc.
EJSkin Lookup
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY,
“com.ejskin.context.SkinnyInitialContextFactory"
);
p.put(Context.PROVIDER_URL,
“ejs://ejs.ejs.com:666");
Context ctx = new InitialContext(p);
SkinnyAppp app =
(SkinnyApp)ctx.lookup(“SkinyApp.fore”);
13. 13
Copyright 2000 SyncTank Solutions, Inc.
Resolving Objects
• Once you have a context any lookup is a relative search.
• user.russell.castagnaro.wallet can be resolved from:
– The initial context as
ctx.lookup(“user.russell.castagnaro.wallet”);
– A subcontext “user.russell” as ctx.lookup(“castagnaro.wallet”);
• Access a sub-context using the lookup method
from any context.
Context ctx = new InitialContext(p);
Context sub = ctx.lookup("user");
sub = sub.lookup("russell"); sub = sub.lookup(”castagnaro");
Object o = sub.lookup("wallet");
Copyright 2000 SyncTank Solutions, Inc.
JNDI Perusal
• It is possible to dynamically access all of
the objects bound into the JNDI tree with
two overloaded methods:
– public abstract NamingEnumeration list(java.lang.String) throws
NamingException;
– public abstract NamingEnumeration list(javax.naming.Name) throws
NamingException;
– public abstract NamingEnumeration listBindings(java.lang.String) throws
NamingException;
– public abstract NamingEnumeration listBindings(javax.naming.Name)
throws NamingException;
• There is a very large difference between
the two methods!
14. 14
Copyright 2000 SyncTank Solutions, Inc.
JNDI Perusal
• listBindings()
– Returns an enumeration of Binding objects.
– Bindings contain the actual object* from the tree!
– May take a long time!
• list()
– Returns an Enumeration of NameClassPair objects.
– Access to the Name and class, but not the object.
– Faster than the alternative, like a ‘shallow get.’
* Remote objects are an exception.
Copyright 2000 SyncTank Solutions, Inc.
JNDI Perusal Example Code
public static void list(Context ctx,StringBuffer sb) {
try {
NamingEnumeration enum = ctx.listBindings("");
while (enum.hasMore()) {
Binding binding = (Binding)enum.next();
Object obj = (Object)binding.getObject();
if (obj instanceof Context) {
sb.append("---> ");
sb.append(binding.getName());
sb.append("."); list((Context)obj,_sb);
} else
{sb.append(binding.getName()); sb.append("n"); }
}
} catch (NamingException e) {
System.out.println(e);
}
}
15. 15
Copyright 2000 SyncTank Solutions, Inc.
JNDI Perusal Output
---> javax.--->
jts.UserTransaction
--->
transaction.UserTransaction
--->
jms.QueueConnectionFactory
TopicConnectionFactory
PrePackagedSessionEJB_EO
---> weblogic.
---> fileSystem.
---> ejb.EJBManager
---> common.T3Services
---> jdbc.JdbcServices
---> connectionPool.ejbpool
cs1
demoPool
cs
--->
jts.CoordinatorFactory[]
CoordinatorFactory
---> server.myserver
WebLogic
---> rmi.--->
jms.ServerSessionPoolFactory
---> jndi.
--->
internal.RemoteContextFactor
y
RemoteContextFactory
Copyright 2000 SyncTank Solutions, Inc.
Adding Objects
• You can use the bind() or rebind() methods to
add objects to the tree.
• If an object extends java.io.Serializable, it is
copied and placed into the tree.
• If an object extends java.rmi.Remote, a copy of
the stub is placed into the tree.
• rebind() will automatically overwrite an existing
object.
• bind() throws a
javax.naming.NamingException
16. 16
Copyright 2000 SyncTank Solutions, Inc.
Adding Objects
public static void main(String args[]) throws java.rmi.RemoteException{
Hashtable ht = new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL, "t3://localhost:7001");
try {
Context ic = new InitialContext(ht);
//serializable, an actual copy put into the tree
ic.bind("Object1",new String("Object1"));
ic = ic.createSubContext(“foo”);
//remote, a copy of the stub placed in the tree
ic.bind("Trivial",new TrivialImpl("Trivial!"));
} catch (NamingException e){
System.out.println(e.getMessage());
}
}
Copyright 2000 SyncTank Solutions, Inc.
Other Features
• Use unbind() to remove an object from the
tree.
• Use rename() to change its registered
name.
• Use custom startup classes to bind
objects into the tree upon start up.
• Use custom properties to automatically
bind objects into the tree.
17. 17
Copyright 2000 SyncTank Solutions, Inc.
Other Features
• Removing Items from the JNDI Tree
try {
Context ic = new InitialContext(ht);
ic.unbind(data);
System.out.println(data+ " successfully unbound.");
} catch (NamingException e) ..
• Renaming
try {
Context ic = new InitialContext(ht);
ic.rename(oldName, newName);
} catch (NamingException e) ..
Copyright 2000 SyncTank Solutions, Inc.
Local Data Access
• Accessing local data using constants
requires recompilation to change those
values
public static String SOME_VALUE=“foo”;
• Using JNDI gives you the freedom to pin
values that need to be shared, without
access to:
– System properties
– File Systems
– Custom Classes
18. 18
Copyright 2000 SyncTank Solutions, Inc.
Local Data Access
• Enterprise Java Beans require the use of
this JNDI for deployment values.
• Allows deployment specialists to change
values without recompilation.
• EJB deployment descriptor snippet:
<env-entry>
<env-entry-name>foo</env-entry-name>
<env-entry-type>String</env-entry-type>
<env-entry-value>bar</env-entry-value>
</env-entry>
Copyright 2000 SyncTank Solutions, Inc.
Local Data Access
• Use a local context and lookup the object
by prepending “java:comp/env”
ctx = new InitialContext();
String foo = (String)ctx.lookup(“java:comp/env.foo”);
19. 19
Copyright 2000 SyncTank Solutions, Inc.
Using Custom Startup Classes
• Using a custom WebLogic startup Class
public String startup(String _name, java.util.Hashtable
_args) throws Exception {
TrivialImpl o = new TrivialImpl();
System.out.println("TrivialImpl instanciated..");
Context context = getInitialContext();
context.rebind(_name, o);
System.out.println("Bound..");
return ("TrivialImpl bound to the name "+_name);
}
public void setServices(weblogic.common.T3ServicesDef
services){}
Copyright 2000 SyncTank Solutions, Inc.
Using a Startup Servlet
public void init(ServletConfig config) throws ServletException {
super.init(config);
String className = config.getInitParameter("CLASS_NAME");
String jndiName = config.getInitParameter("JNDI_NAME");
if (className != null && jndiName != null) {
try{
Object o = Class.forName(className).newInstance();
Context ctx = new InitialContext();
ctx.rebind(jndiName,o);
log("StartupServlet has bound "+
className +" into”+ the JNDI tree as "+ jndiName);
} catch (Exception ne) {
throw new ServletException(ne);
}
}
20. 20
Copyright 2000 SyncTank Solutions, Inc.
Singletons
• You need one and only one instance of
a particular class.
• You want to provide access to
distributed applications/ services.
• Don’t make static methods! Make the
class an RMI object.
• Bind the object’s implementation into
the JNDI tree.
• Essentially what happens for EJBHome
interfaces.
Copyright 2000 SyncTank Solutions, Inc.
CORBA Objects
• When accessing CORBA objects, things
used to be more complicated.
• RMI over IIOP, included in Java 2,
solves this problem.
• Narrowing the object maps it from a
CORBA object to a Java object auto-
magically.
21. 21
Copyright 2000 SyncTank Solutions, Inc.
Narrowing
• If you access services using RMI over
IIOP (WebSphere, Iona, etc.).
• If you use HomeHandle or Handle
objects (EJB 1.1).
• Use PortableObject.narrow()
• Pass an Object and the class you
expect from the remote method call.
Copyright 2000 SyncTank Solutions, Inc.
Class Narrowing
ObjectOutputStream stream = ...;
Account account = ...;
Handle handle = account.getHandle();
stream.writeObject(handle);
// A client can read the handle from stable storage, and use the
// handle to resurrect an object reference to the
// account entity object.
//
ObjectInputStream stream = ...;
Handle handle = (Handle) stream.readObject(handle);
Account account = (Account)javax.rmi.PortableRemoteObject.narrow(
handle.getEJBObject(), Account.class);
account.debit(100.00);
22. 22
Copyright 2000 SyncTank Solutions, Inc.
JDBC and JNDI
• It is possible to use JNDI to store JDBC
connection objects:
SampleDataSource sds = new SampleDataSource();
sds.setServerName(“BEQ-LOCAL”);
sds.setDatabaseName(“demo”);
Context ctx = new InitialContext();
ctx.bind(“EmployeeDB”, sds);
• Application servers typically feature
datasource publishing:
weblogic.jdbc.TXDataSource.ejbDataSource=ejbPool
weblogic.jdbc.DataSource.ejbPool=ejbPool
Copyright 2000 SyncTank Solutions, Inc.
JDBC and JNDI
• Use them later to avoid prior knowledge of
driver information:
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup(“ejbDataSource”);
Connection con = ds.getConnection();
23. 23
Copyright 2000 SyncTank Solutions, Inc.
Events
• JNDI Events provide local or remote
callback functionality.
• Similar to the event model used in Swing.
• Uses subclasses of the
javax.naming.NamingListener interface.
• NamingListeners:
– NamespaceChangeListener
– ObjectChangeListener
– UnsolicitedNotificationListener
Copyright 2000 SyncTank Solutions, Inc.
Events
• JNDI Events require the use of a different
type of context.
• New Context interfaces:
– EventContext for standard naming services
– EventDirContext for LDAP service
• Access Contexts in a familiar way:
EventDirContext edc = (EventDirContext)
(new InitialDirContext(env).lookup("ou=People"));
24. 24
Copyright 2000 SyncTank Solutions, Inc.
JNDI Gotchas
• Use rebind() wisely.
• Know the URL and InitialContextFactory class
name.
• When using advanced features (LDAP, etc.)
place the correct resources in your classpath.
.librmiregistry.jar;.libproviderutil.jar;
.libjndi.jar;.libjaas.jar;.libldap.jar;
.libldapbp.jar;.libfscontext.jar
• J2EE has made deploying JNDI services
much easier, look for vendors to support
advanced features 2Q 2000.
Copyright 2000 SyncTank Solutions, Inc.
Review
• JNDI is used for all advanced J2EE
features.
• JNDI provides an easy method of accessing
remote or local resources.
• Use bind() or rebind() to register objects.
• Use lookup() to resolve objects.
• Use your server vendors startup facilities for
initial JNDI registration.
25. 25
Copyright 2000 SyncTank Solutions, Inc.
Finally
• Thanks for attending.
• Live in Hawaii or Bay Area? Do you like
this stuff? Email your resume to us!
• Source Code Available:
– http://www.synctank.com/softwaresummit
– russell@4charity.com
• Aloha!