![]() |
![]() |
|
Programming with WebLogic JNDI
This section discusses the following topics:
The WebLogic Server JNDI Service Provider Interface (SPI) provides an InitialContext implementation that allows remote Java clients to connect yo WebLogic Server. The client can specify standard JNDI environment properties that identify a particular WebLogic Server deployment and related connection properties for logging in to WebLogic Server.
To participate in a session with WebLogic Server, a Java client must be able to get an object reference for a remote object and invoke operations on the object. To accomplish this, the client application code must perform the following procedure:
The following sections discuss JNDI client operations for connecting to a specific WebLogic Server. For information about using JNDI in a cluster of WebLogic Servers, see Using WebLogic JNDI from a Client in a Clustered Environment.
Before you can use JNDI to access an object in a WebLogic Server environment, you must load the object into the WebLogic Server JNDI tree. For instructions loading objects in the JNDI tree, see Managing JNDI.
Setting Up JNDI Environment Properties for the InitialContext
The first task that must be performed by any Java client application is to create environment properties. The InitialContext factory uses various properties to customize the InitialContext for a specific environment. You can set these properties either by using a hash table or the set() method of a WebLogic Environment object. These properties, which are specified name-to-value pairs, determine how the WLInitialContextFactory creates the Context. The following properties are used to customize the InitialContext:
You can use the same properties on either a client or a server. If you define the properties on a server-side object, a local Context is used. If you define the properties on a client or another WebLogic Server server, the Context delegates to a remote Context running on the WebLogic Server specified by the Context.PROVIDER_URL property.
Listing 2-1 shows how to obtain a Context using the properties Context.INITIAL_CONTEXT_FACTORY and Context.PROVIDER_URL.
Listing 2-1 Obtaining a Context
Context ctx = null;
Hashtable ht = new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL,
"t3://localhost:7001");
try {
ctx = new InitialContext(ht);
// Use the context in your program
}
catch (NamingException e) {
// a failure occurred
}
finally {
try {ctx.close();}
catch (Exception e) {
// a failure occurred
}
}
Additional WebLogic-specific properties are also available for configuring security parameters and controlling how objects are bound into the cluster-wide JNDI tree. Note that bindings may or may not be replicated across the JNDI tree of each server within the cluster. Properties such as these are identified by constants in the weblogic.jndi.WLContext class. For more information about JNDI-related clustering issues, see Using WebLogic JNDI from a Client in a Clustered Environment.
Creating a Context Using a Hash Table
You can create a Context with a hash table in which you have specified the properties described in Setting Up JNDI Environment Properties for the InitialContext.
To do so, pass the hash table to the constructor for InitialContext. The property java.naming.factory.initial is used to specify how the InitialContext is created. To use WebLogic JNDI, you must always set the java.naming.factory.initial property to weblogic.jndi.WLInitialContextFactory. This setting identifies the factory that actually creates the Context.
Creating a Context Using a WebLogic Environment Object
You can also create a Context by using a WebLogic environment object implemented by the weblogic.jndi.environment interface. Although the environment object is WebLogic-specific, it offers the following advantages:
The WebLogic Environment object provides the following defaults:
If you want to create InitialContext with these defaults, write the following code:
Environment env = new Environment();
Context ctx = env.getInitialContext();
If you want to set only a WebLogic Server to a Distributed Name Service (DNS) name for client cluster access, write the following code:
Environment env = new Environment();
env.setProviderURL("t3://myweblogiccluster.com:7001");
Context ctx = env.getInitialContext();
Creating a Context from a Server-Side Object
You may also need to create a Context from an object (an Enterprise JavaBean (EJB) or Remote Method Invocation (RMI) object) that is instantiated in the Java Virtual Machine (JVM) of WebLogic Server. When using a server-side object, you do not need to specify the Context.PROVIDER_URL property. User names and passwords are required only if you want to sign in as a specific User. Server-side contexts run in the context of WebLogic Server.
To create a Context from within a server-side object, you first must create a new InitialContext, as follows:
Context ctx = new InitialContext();
You do not need to specify a factory or a provider URL. By default, the context is created as a Context and is connected to the local naming service.
Associating a WebLogic User with a Security Context
Note: BEA recommends using the Java Authentication and Authorization Service (JAAS) rather than JNDI to associate a User with a security context. For more information, see Programming WebLogic Security.
Using the Context to Look Up a Named Object
Every Java client application must obtain an initial object that provides services for the application. An object cannot not be looked up, however, unless it is loaded in the WebLogic Server namespace. For more information, see Managing JNDI in the Administration Guide.
The lookup() method on the Context is used to obtain named objects. The argument passed to the lookup() method is a string that contains the name of the desired object. Listing 2-2 shows how to retrieve an EJB named ServiceBean.
Listing 2-2 Looking Up a Named Object
try {
ServiceBean bean = (ServiceBean)ctx.lookup("ejb.serviceBean");
}
catch (NameNotFoundException e) {
// binding does not exist
}
catch (NamingException e) {
// a failure occurred
}
Using a Named Object to Get an Object Reference
EJB client applications get object references to EJB remote objects from EJB Homes. RMI client applications get object references to other RMI objects from an initial named object. Both initial named remote objects are known to WebLogic Server as factories. A factory is any object that can return a reference to another object that is in the WebLogic namespace.
The client application invokes a method on a factory to obtain a reference to a remote object of a specific class. The client application then invokes methods on the remote object, passing any required arguments.
Listing 2-3 contains a code fragment that obtains a remote object and then invokes a method on it.
Listing 2-3 Using a Named Object to Get an Object Reference
ServiceBean bean = ServiceBean.Home.create("ejb.ServiceBean")
Servicebean.additem(66);
After clients finish working with a context, the client should close the context in order to release resources. We recommend that you use a finally{} block and wrap the close() method in a try{} block. If you attempt to close a context that was never instantiated because of an error, the Java client application throws an exception.
In Listing 2-4, the client closes the context, releasing the resource being used.
Listing 2-4 Closing the Context
try {
ctx.close();
} catch (Exception e) {
//a failure occurred
}
Using WebLogic JNDI in a Clustered Environment
The intent of WebLogic JNDI is to provide a naming service for J2EE services, specifically EJB, RMI, and Java Messaging Service (JMS). Therefore, it is important to understand the implications of binding an object to the JNDI tree in a clustered environment.
The following sections discuss how WebLogic JNDI is implemented in a clustered environment and offer some approaches you can take to make your own objects available to JNDI clients.
WebLogic RMI is the enabling technology that allows clients in one JVM to access EJBs and JMS services from a client in another JVM. RMI stubs marshal incoming calls from the client to the RMI server object. To make J2EE services available to a client, WebLogic Server binds an object-in this case, an RMI stub for a particular service-into its JNDI tree under a particular name. WebLogic Clusters extend WebLogic JNDI from a single server to a server that contains all the offerings provided by the cluster. This extension is accomplished by replicating the bindings the RMI stubs-bound in each WebLogic Server to all the other WebLogic Servers in the cluster. When a client connects to a cluster, it is actually connecting to one of the WebLogic Servers already in the cluster. Because the JNDI tree for this WebLogic Server contains the stubs for all services offered by the other WebLogic Servers in the cluster in addition to its own services, the cluster appears to the client as one WebLogic Server hosting all of the cluster-wide services. When a new WebLogic Server joins a cluster, each WebLogic Server already in the cluster is responsible for sharing information about its own services to the new WebLogic Server. With the information collected from all the other servers in the cluster, the new server may create its own copy of the cluster-wide JNDI tree.
A clustered service provides failover and load balancing. To be clustered, a service must be deployed on multiple WebLogic Servers and bound to the same name within the JNDI tree. With clustered services, special clusterable stubs use the chosen algorithm for load balancing and failover.
In a clustered environment, WebLogic JNDI is designed specifically to work efficiently with RMI stubs. RMI stubs significantly affect how WebLogic JNDI is implemented in a clustered environment:
Making Custom Objects Available to a WebLogic Server Cluster
When you bind a custom object into a JNDI tree in a WebLogic Server cluster, the object is handled as described in Clustering J2EE Services. However, custom object often have characteristics not shared by RMI stubs. Therefore, the default behavior of WebLogic JNDI within a cluster may not be suitable for a custom object.
Suppose the custom object needs to be accessed only by EJBs that are deployed on only one WebLogic Server. Obviously it is unnecessary to replicate this custom object throughout all the WebLogic Servers in the cluster. In fact, you should avoid replicating the custom object in order to avoid any performance degradation due to unnecessary server-to-server communication. To create a binding that is not replicated across WebLogic Servers in a cluster, you must specify the REPLICATE_BINDINGS property when creating the context that binds the custom object to the namespace. Listing 2-5 illustrates the use of the REPLICATE_BINDINGS property.
Listing 2-5 Using the REPLICATE_BINDINGS Property
Hashtable ht = new Hashtable();
//turn off binding replication
ht.put(WLContext.REPLICATE_BINDINGS, "false");
try {
Context ctx = new InitialContext(ht);
//bind the object
ctx.bind("my_object", MyObect);
} catch (NamingException ne) {
//failure occured
}
When you are using this technique and you need to use the custom object, you must explicitly obtain an Initial Context for the WebLogic Server. If you connect to any other WebLogic Server in the cluster, the binding does not appear in the JNDI tree.
If you need to your custom object accessible from any WebLogic Server in the cluster, use one of the following techniques:
The technique you use has an effect on your application's performance and the availability of the custom object as described in the following sections.
Relying on WebLogic JNDI to copy an object from one WebLogic Server to all of the other WebLogic Servers in a cluster can have an adverse effect on performance due to additional server-to-server communication. The effect on performance depends on the size of the custom object. If the custom object is large or dynamic in size, BEA recommends avoid this technique. Instead, you can use the design pattern described in Data Caching Design Pattern.
When using WebLogic JNDI to replicate bindings, the bound object will be handled as if it owned by the host WebLogic Server. If the host WebLogic Server fails, the custom object is removed from all the WebLogic Servers in the cluster. While this is the appropriate behavior in cases where the bound object is an RMI stub referring back to the host WebLogic Server, it may not be the appropriate behavior for your custom object. This behavior can have an adverse effect on the availability of the custom object. If the availability of the custom object is critical, you can use the design pattern described in Data Caching Design Pattern.
A common task in web applications is to cache data used by multiple objects for a period of time to avoid the overhead associated with data computation or connecting to another service. (For caching JDBC accessible data, you should use read-only entity EJBs. For more information, see Programming WebLogic Enterprise JavaBeans.)
Suppose you have designed a non-RMI, data caching object that performs well on single WebLogic Server and you would like to use this same object within a WebLogic cluster. If you bind the data caching object in the JNDI tree of one of the WebLogic Servers, WebLogic JNDI will, by default, copy the object to each of the other WebLogic Servers in the cluster. It is important to note that since this is not an RMI object, what you are binding into the JNDI tree (and copying to the other WebLogic Servers) is the object itself, not a stub that refers to a single instance of the object hosted on one of the WebLogic Servers. For the sake of performance and availability is often desirable to avoid using WebLogic JNDI's binding replication to copy large custom objects with high availability requirements to all of the WebLogic Servers in a cluster.
As an alternative, you can deploy a separate instance of the custom object on each of the WebLogic Servers in the cluster. When binding the object to each WebLogic Server's JNDI tree, you should make sure to turn off binding replication as described in the Making Custom Objects Available to a WebLogic Server Cluster section. In this design pattern, each WebLogic Server has a copy of the custom object but you will avoid copying large amounts of data from server to server.
Each instance of the object should maintain its own logic for when it needs to refresh its cache independently of the other data cache objects in the cluster. For example, suppose a client accesses the data cache on one WebLogic Server. It is the first time the caching object has been accessed, so it computes or obtains the information and saves a copy of the information for future requests. Now suppose another client connects to the cluster to perform the same task as the first client only this time the connection is made to a different WebLogic Server in the cluster. If this the first time this particular data caching object has been accessed, it will need to compute the information regardless of whether other data caching objects in the cluster already have the information cached. Of course, for any future requests, this instance of the data cache object will be able to refer to the information it has saved.
Exactly-Once-Per-Cluster Design Pattern
In some cases, it is desirable to have a service that appears only once in the cluster. This is accomplished by deploying the service on one machine only. For RMI objects, you can use the default behavior of WebLogic JNDI to replicate the binding (the RMI stub) and the single instance of your object will be accessible from all WebLogic Servers in the cluster. This is referred to as a pinned service. For non-RMI objects, make sure that you use the REPLICATE_BINDINGS property when binding the object to the namespace. In this case, you will need to explicitly connect to the host WebLogic Server to access the object. Alternatively, you can create an RMI object that is deployed on the same host WebLogic Server that can act as a proxy for your non-RMI object. The stub for the proxy can be replicated (using the default WebLogic JNDI behavior) allowing clients connected to any WebLogic Server in the cluster to access the non-RMI object via the RMI proxy.
This design pattern for an exactly-once-per-cluster service presents an additional challenge for services with high availability requirements. Since the failover feature of WebLogic Clusters relies on having multiple deployments of each clustered service, failover for an exactly-once-per-cluster service will not be available. For services that require high availability, it is suggested that you implement a hardware, High-Availability (HA) framework for the host WebLogic Server. The framework allows WebLogic Server to be restarted in the event of a failure with a minimal amount of disruption to availability of the service.
Using WebLogic JNDI from a Client in a Clustered Environment
The JNDI binding for an object can appear in the JNDI tree for one WebLogic Server in the cluster, or it can be replicated to all the WebLogic Servers in the cluster. If the object of interest is bound in only one WebLogic Server, you must explicitly connect to the host WebLogic Server by setting the Context.PROVIDER_URL property to the host WebLogic Server's URL when creating the Initial Context, as described in Using WebLogic JNDI from a Java Client.
In most cases, however, the object of interest is either a clustered service or a pinned service. As a result, a stub for the service is displayed in the JNDI tree for each WebLogic Server in the cluster. In this case, the client does not need to name a specific WebLogic Server to provide its naming service. In fact, it is best for the client to simply request that a WebLogic Cluster provide a naming service, in which case the context factory in WebLogic Server can choose whichever WebLogic Server in the cluster seems most appropriate for the client. Currently, a naming service provider is chosen within WebLogic using DNS round-robining.
The context that is returned to a client of clustered services is, in general, implemented as a failover stub that can transparently change the naming service provider if a failure (such as a communication failure) with the selected WebLogic Server occurs.
Listing 2-6 shows how a client uses the cluster's naming service.
Listing 2-6 Using the Naming Service in a WebLogic Cluster
Hashtable ht = new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL, "t3://acmeCluster:7001");
try {
Context ctx = new InitialContext(ht);
// Do the client's work
}
catch (NamingException ne) {
// A failure occurred
}
finally {
try {ctx.close();}
catch (Exception e) {
// a failure occurred
}
}
The hostname specified as part of the provider URL is the DNS name for the cluster that can be defined by the weblogic.cluster.name property. This command-line property is set when the cluster is started. It maps to the list of hosts providing naming service in this cluster. For more information, see Configuring WebLogic Servers and Clusters.
In Listing 2-6, the cluster name acmeCluster is used to connect to any of the WebLogic Servers in the cluster. The resulting Context is replicated so that it can fail over transparently to any WebLogic Server in the cluster.
An alternative method of specifying the initial point of contact with the WebLogic Cluster is to supply a comma-delimited list of DNS Server names or IP addresses, as shown in the following sample code:
ht.put(Context.PROVIDER_URL, "t3://acme1,acme2,acme3:7001");
Notice that all the WebLogic Servers must listen on the same port, as specified at the end of the URL.
|
Copyright © 2000 BEA Systems, Inc. All rights reserved.
|