Each WebLogic server maintains a local JNDI tree. Typically, you will bind various J2EE resources to the JNDI tree, such as JDBC data sources, EJB home objects, JMS connection factories, and more. You can use the Administration Console to view the contents and structure of the JNDI tree on a server. Select a server from the left frame of the Administration Console, right-click the server node, and choose the “View JNDI tree” option from the pop-up menu. This launches a new window that displays the contents of the JNDI tree for the selected server. You can now navigate the JNDI tree and view the various objects bound to it.
In the following sections, you will learn how to programmatically establish a connection to WebLogic’s JNDI server, from both an external client and an internal J2EE component, and how to use the connection to locate and bind objects. As the JNDI tree also permits authorization policies, we also will look at a few security issues surrounding the use of a JNDI tree.
In
order to access WebLogic’s JNDI tree, you need to
establish a standard JNDI InitialContext
representing the context root of the server’s
directory service. You can do this by passing a
Hashtable
of property/value pairs to the
javax.naming.InitialContext( )
constructor. The
Hashtable
represents environment properties that
are used to establish the context; in an external client, you
typically will need to supply at least a URL property that points to
a server you wish to access, and a context factory class that
represents the service provider to use in the construction of the
context.
Example 4-1 shows how a Java client can obtain an initial JNDI context to a WebLogic Server.
Example 4-1. Obtaining the initial JNDI context
import javax.naming.*; private static InitialContext ctx = null; ... public static InitialContext getInitialContext( ) throws NamingException { if (ctx == null) { Hashtable env = new Hashtable( ); env.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory"); env.put(Context.PROVIDER_URL,
"t3://myserver:8001"); ctx = new InitialContext(env); } return ctx; }
The PROVIDER_URL
property specifies the URL of the
server whose JNDI tree we want to access. The
INITIAL_CONTEXT_FACTORY
property contains the
fully qualified class name of WebLogic’s context
factory, specifying the service provider to use. If you need to
access WebLogic’s JNDI tree, you should always
establish the context using the class name
weblogic.jndi.WLInitialContextFactory
.
Tip
It is customary to cache the InitialContext
object
once it’s created, and to use the cached object for
subsequent requests for the initial JNDI context.
Table 4-1 provides the list of environment properties that may be used to customize the initial JNDI context. In the next section, we will examine other properties relevant to the use of JNDI in a clustered environment.
Table 4-1. Environment properties for the initial JNDI context
Context property |
Description |
Default |
---|---|---|
|
Use this property to specify the name of the initial context factory.
|
none |
|
Use this property to set the URL of the WebLogic Server or cluster that you want to contact. |
t3://localhost:7001 |
|
If the client needs to authenticate itself to the server, use this property to specify the identity of a WebLogic user. |
|
|
Use this property to specify the password for the WebLogic user. |
|
WebLogic providers a helper class,
weblogic.jndi.Environment
, which eases the
creation of the initial context. The class provides type-safe methods
for setting and accessing common JNDI properties, and assumes
sensible defaults for many of the JNDI properties needed to access
the JNDI tree on WebLogic Server. The following code sample shows how
to obtain the initial JNDI context using the
Environment
object:
Environment env = new Environment( );
env.setProviderUrl("t3://servername:7001");
env.setSecurityPrincipal("jon");
env.setSecurityCredentials("jonpassword");
Context ctx = env.getInitialContext( );
...
A client should use the close( )
method to release
any resources allocated to the JNDI Context
. We
recommend that you always invoke the close( )
method when you no longer require the JNDI context:
Context ctx = null;
try {
// Create the context using the code in Example 4.1
ctx = getInitialContext( );
//now use the JNDI Context to look up objects
}
catch (NamingException ene) {
//handle JNDI Exceptions
}
finally {
try {
if (ctx != null) ctx.close( );
}
catch (Exception ignored) {}
}
Server-side objects, such as servlets and EJBs, do not need to
provide any environment properties when creating an initial JNDI
context. When a server-side object invokes the
InitialContext( )
constructor, the JNDI context
will always connect to the local server that hosts the server-side
object. This means that if you need only to access objects bound to
the local JNDI tree, a server-side object can simply create the
initial JNDI context, without explicitly specifying any environment
properties. For example, if a servlet needs to look up the home
object for an EJB that is deployed on the same server, a call to the
default InitialContext
constructor will suffice:
Context ctx = new InitialContext( );
Object home = ic.lookup("java:comp/env/ejb/MyEJBHome");
MyEJBHome ejbHome = (MyEJBHome)
PortableRemoteObject.narrow(home, org.foo.bar.MyEJBHome.class);
// now use the EJB home object to obtain an EJB instance
Of course, you could pass the security credentials of a valid WebLogic user if you need to establish and use the context under a particular security scope.
As you’ll see later in Chapter 17, WebLogic allows an administrator to set up authorization policies that can restrict access to any arbitrary branch of the JNDI tree. You can view and change these policies by using the Administration Console’s JNDI viewer. Right-click a node to view the policy for that node. As the policies are inherited, by applying a policy to the root node you will effectively be applying it to all nodes of the tree. By applying such a policy, you are creating an authorization requirement on the actual lookup in the JNDI tree. You also can create authorization policies that apply to the objects bound in the JNDI tree itself. So, for instance, you can create a policy that restricts the lookup of a connection pool, and another that restricts the use of the connection pool.
The default policy on the root of the JNDI tree grants access to the
anonymous user (in fact, to the group Everyone
).
Thus, if you do not specify the credentials of a WebLogic user when
establishing an initial context, the anonymous user is automatically
used to verify access control to the JNDI tree. So, by default, you
do have the necessary authorization to access the JNDI tree. If the
thread already has been associated with a WebLogic user, that
security principal is used for all authorization checks when you
subsequently access the JNDI tree. Hence, if a security policy has
been defined on a specific branch of the JNDI tree, you need to
ensure that a valid principal is associated with the thread, and that
it has sufficient privileges to access the branch. There are two ways
in which you can establish an identity under which the JNDI tree
ought to be
accessed:
Supply values for the
SECURITY_PRINCIPAL
andSECURITY_CREDENTIALS
environment properties when creating an initial context. When you create a JNDI context in this way, the security scope is valid for the lifetime of the context. It is terminated when you invoke theclose( )
method on theContext
object. The security context actually is associated with the thread running the code. This has important implications. Establishing a new context will replace any previous security context associated with the thread. Thus, you should not try to establish a nested context using differing security principals. In that case, all code will run using the most recently created context.Use the
weblogic.security.Security.runAs( )
method to apply a security context to your code. In this case, you should use the standard JAAS login procedure to create and populate a security subject. TherunAs( )
method accepts two arguments: the code that needs to be executed, and the subject under which it ought to be executed. The thread’s security context is then propagated to any subsequent JNDI contexts created from within your code. Any such JNDI lookup will be authorized using the credentials of the current subject associated with the thread.
JAAS-based authentication is covered in Chapter 17, which also discusses how to use SSL certificates and mutual authentication to provide additional security when creating a JNDI context.
Once
you have obtained the initial JNDI context, you can look up any named
object bound in the context. Example 4-2 shows how
you can look up a transactional data source and
UserTransaction
from the JNDI tree, and use them
to create JDBC connections that participate in a JTA transaction.
Example 4-2. Using the initial JNDI context to look up a named object
javax.naming.Context ctx = null; javax.transaction.UserTransaction tx = null; javax.sql.DataSource ds = null; java.sql.Connection con = null; //set up the JNDI environment try { ctx = new InitialContext(env); //use the JNDI tree to look up a configured TxDataSource ds = (DataSource) ctx.lookup("myTxDs"); //use the JNDI tree to initiate a new JTA transaction tx = (UserTransaction) ctx.lookup("java:comp/UserTransaction"); //initiate the transaction tx.begin( ); con = ds.getConnection( ); //perform your JDBC updates here... //commit the transaction tx.commit( ); } catch (Exception e) { // exceptions code goes here } finally { try { if (ctx != null) ctx.close( ); //release other JDBC resources here... } catch (Exception ignored) {} }
You also may use the Context
object to bind custom
objects to WebLogic’s JNDI context. The following
code shows how you can bind an instance of a custom Java class,
com.oreilly.custom.Foo
, to the JNDI tree under the
name
myObj
:
try {
// env represents an instance of weblogic.jndi.Environment
ctx = env.getInitialContext( );
ctx.bind("myObj", new com.oreilly.custom.Foo( ));
}
catch (NamingException e) {
//handle exception in case an object is already bound under the same name
}
A call to the bind( )
method for custom objects
will not succeed if another object has already been bound to the JNDI
tree under the same name. Instead, you should use the
rebind( )
method to overwrite any previous binding
and bind the new custom object under the same name:
try {
ctx = env.getInitialContext( );
ctx.rebind("myObj", new com.oreilly.custom.Foo( ));
}
catch (NamingException e) {
}
Remember that a custom object can be
bound to the JNDI tree only if its class implements the
java.io.Serializable
interface. Typically, you
should implement a WebLogic startup class that binds any needed
custom objects at server startup. This approach is described later in
this chapter in Section 4.3.2
."
Get WebLogic: The Definitive Guide now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.