Monday, 21 March 2011

Core Java: Thread Intro & Lifecycle


THREADING

A multithreaded program contains two or more parts that can run concurrently. Each part of such a program is called a thread and each thread defines a separate path of execution. Thus, multithreading is a specialization form of multi tasking.
There are two distinct types of multitasking: process-based and thread-based. A process is a program that is executing. Thus, process-based multitasking is the feature that allows your computer to run two or more programs concurrently. For example, process based multitasking enables us to run MS-word for editing a word document at the same time running media player to listen some sweet music. In processed based multitasking a program is the smallest unit of code that can be dispatched by a scheduler. (A process migrates between the various scheduling queues throughout its lifetime. The operating system must select, for scheduling purposes, processes from these queues in some fashion. The appropriate scheduler carries out the selection process).
On the other hand in thread-based multitasking system, the thread is the smallest unit of dispatch able code. That is, a single program can perform two or more tasks simultaneously. For instance, a user can simultaneously type in characters and run the spell checker within the same process.
A thread, sometimes called a lightweight process (LWP), because the threads share the common memory space. The memory allocated to the main thread will be shared by all other child threads. Whereas in case of Process the child process are in need to allocate the seperate memory space.
It is a basic unit of CPU utilization; it comprises a thre
ad ID, a program counter, a register set, and a stack. It shares with other threads belonging to the same process its code section, data section, and other operating system resources, such as open files and signals. A traditional (or heavyweight) process has a single thread of control. If the process has multiple threads of control, it can do more than one task at a time. Hence a multitasking thread requires fewer overheads than multitasking processes.

LIFE CYCLE OF A THREAD

During the lifetime of a thread, there are many states it can enter. They include:
  1. Newborn state
  2. Runnable state
  3. Running state
  4. Blocking state
  5. Dead state
A thread is always in one of these five states. It can move from one state to another
via a variety of ways as shown in the following figure:
Newborn State:
When we create a thread object, the thread is born and is said to be in newborn state. The thread is not yet scheduled for running. At this state, we can do only one of the following things with it:
Schedule it for running using start( ) method.
Kill it by using stop( )
If scheduled, it moves to the Runnable state. If we attempt to use any other method at this stage, an exception will be thrown.

Runnable State:
The runnable state means that the thread is ready for execution and is waiting for execution and i.e. for the availability of the processor. That is, the thread has joined the queue of threads that are waiting for execution. Java assigns each thread a priority (an integer) that determines how that thread should be treated with respect to the others. A thread priority is used to decide when to switch from one running thread to the next. This is called context switch. The rule that determine when a context switch takes place are simple:
A thread can voluntarily give up control.
A higher-priority thread can preempt a thread.
In case of threads whit equal priority, some OS’ like Win-98 allocate time-slice automatically for them in round-robin (US tournament in which each competitor plays every other.) fashion. On some other OS’, threads of equal priority must voluntarily yield control to other thread with equal priority. However, if we want a thread to give up control to another thread of equal priority before its turn comes, we can do so by using the yield( ) method.

Running State:
Running means that the processor has given its time to the thread for its execution. The thread runs until it relinquish (v. to give sth. up) control on its own or it is preempted (v. to prevent sth. happening by taking action to stop it) by a higher priority thread. A running thread may relinquish its control in one of the following situation.
  1. It has been suspended using suspend( ) method. A suspended thread can be revived by using the resume( ) method. This approach is useful when we want to suspend a thread for some time due to certain reason, but do not want to kill it.
  2. It has been made to sleep. We can put a thread to sleep for a specified time period using the method sleep( time ) where time is in milliseconds. This is that the thread is out of queue during this period. The thread re-enters the runnable state as soon as this time period is elapsed.
  3. It has been told to wait until some event occurs. This is done using the wait( ) method. The thread can be scheduled to run again using the notify( ) method.
Blocking State:
A thread is said to be blocked when it is prevented from entering into the runnable state and subsequently the running state. This happens when the thread is suspended, sleeping, or waiting in order to satisfy certain requirements. A blocked thread is considered “not runnable” but not dead there fully qualified to run again.

Dead State:
Every thread has a life cycle. A running thread ends its life when it has completed executing its run( ) method. It is a natural dead. However, we can kill it by sending to stop message to it at any state thus causing a premature death to it. A thread can be killed as soon it is born, or while it is running, or even when it is in “not runnable” (blocked) condition.


Sunday, 20 March 2011

J2ee: HTTP Basics

Requests, Responses, and Headers

HTTP is a simple, stateless protocol. A client, such as a web browser, makes a request, the web server responds, and the transaction is done. When the client sends a request, the first thing it specifies is an HTTP command, called a method, that tells the server the type of action it wants performed. This first line of the request also specifies the address of a document (a URL) and the version of the HTTP protocol it is using. For example:

GET /intro.html HTTP/1.0

This request uses the GET method to ask for the document named intro.html, using HTTP Version 1.0. After sending the request, the client can send optional header information to tell the server extra information about the request, such as what software the client is running and what content types it understands. This information doesn’t directly pertain to what was requested, but it could be used by the server in generating its response. Here are some sample request headers:

User-Agent: Mozilla/4.0 (compatible; MSIE 4.0; Windows 95)
Accept: image/gif, image/jpeg, text/*, */*

The User-Agent header provides information about the client software, while the Accept header specifies the media (MIME) types that the client prefers to accept.

After the headers, the client sends a blank line, to indicate the end of the header section. The client can also send additional data, if appropriate for the method being used, as it is with the POST method. If the request doesn’t send any data, it ends with an empty line.

After the client sends the request, the server processes it and sends back a response. The first line of the response is a status line that specifies the version of the HTTP protocol the server is using, a status code, and a description of the status code. For example:

HTTP/1.0 200 OK

This status line includes a status code of 200, which indicates that the request was successful, hence the description “OK”. Another common status code is 404, with the description “Not Found”—as you can guess, this means that the requested document was not found.

After the status line, the server sends response headers that tell the client things like what software the server is running and the content type of the server’s response. For example:

Date: Saturday, 23-May-98 03:25:12 GMT
Server: JavaWebServer/1.1.1
MIME-version: 1.0
Content-type: text/html
Content-length: 1029
Last-modified: Thursday, 7-May-98 12:15:35 GMT

The Server header provides information about the server software, while the Content-type header specifies the MIME type of the data included with the response. The server sends a blank line after the headers, to conclude the header section. If the request was successful, the requested data is then sent as part of the response. Otherwise, the response may contain human-readable data that explains why the server couldn’t fulfill the request.


GET and POST

When a client connects to a server and makes an HTTP request, the request can be of several different types, called methods. The most frequently used methods are GET and POST. Put simply, the GET method is designed for getting information (a document, a chart, or the results from a database query), while the POST method is designed for posting information (a credit card number, some new chart data, or information that is to be stored in a database).

The GET method, although it’s designed for reading information, can include as part of the request some of its own information that better describes what to get — such as an x, y scale for a dynamically created chart. This information is passed as a sequence of characters appended to the request URL in what’s called a query string. Placing the extra information in the URL in this way allows the page to be book marked or emailed like any other. Because GET requests theoretically shouldn’t need to send large amounts of information, some servers limit the length of URLs and query strings to about 240 characters.

The POST method uses a different technique to send information to the server because in some cases it may need to send megabytes of information. A POST request passes all its data, of unlimited length, directly over the socket connection as part of its HTTP request body. The exchange is invisible to the client. The URL doesn’t change at all. Consequently, POST requests cannot be bookmarked or emailed. In practice, the use of GET and POST has strayed from the original intent. It’s common for long parameterized requests for information to use POST instead of GET to work around problems with overly long URLs. Just remember that GET requests, because they can be bookmarked so easily, should not be allowed to cause damage for which the client could be held responsible. In other words, GET requests should not be used to place an order, update a database, or take an explicit client action in any way.


Other Methods

In addition to GET and POST, there are several other lesser-used HTTP methods. There’s the HEAD method, which is sent by a client when it wants to see only the headers of the response, to determine the document’s size, modification time, or general availability. There’s also PUT, to place documents directly on the server, and DELETE, to do just the opposite. These last two aren’t widely supported due to complicated policy issues. The TRACE method is used as a debugging aid—it returns to the client the exact contents of its request. Finally, the OPTIONS method can be used to ask the server which methods it supports or what options are available for a particular resource on the server.

Saturday, 19 March 2011

J2ee: CGI glimpse

Common Gateway Interface (CGI)

The Common Gateway Interface, normally referred to as CGI, was one of the first practical techniques for creating dynamic content. With CGI, a web server passes certain requests to an external program. The output of this program is then sent to the client in place of a static file.

It’s interesting to note that the ability of CGI programs to create dynamic web pages is a side effect of its intended purpose: to define a standard method for an information server to talk with external applications. This origin explains why CGI has perhaps the worst life cycle imaginable. When a server receives a request that accesses a CGI program, it must create a new process to run the CGI program and then pass to it, via environment variables and standard input, every bit of information that might be necessary to generate a response. Creating a process for every such request requires time and significant server resources, which limits the number of requests a server can handle concurrently.

Even though a CGI program can be written in almost any language, the Perl programming language has become the predominant choice.










Friday, 18 March 2011

DBMS: Candidate Key Determination for a Relation

How to find Cadidate Keys of a Relation using its FDs

In this lession JBS will provide you the way to find candidate keys for a relation...
A candidate key uniquely identifies each row in a relational table. It is a minimal super key. To find a candidate key for a relation, we can use FDs to find a minimal set of attributes in the relation which functionally determines (uniquely identifies) all the attributes in the relation. An attribute always functionally determines itself - trivial but true.

Elmasri & Navathe's Algorithm
According to Elmasri and Navathe, we know how to determine X+, the Closure of X under F where X is a subset of the attibutes in a given relation, and F is a set of functional dependencies specified for the given relation. This algorithm also allows us to find candidate keys using FDs.
We know that, if the closure of a set of attributes, X, in a relation is equal to the set of all the attributes in the relation, we know that X is a superkey of the relation. Moreover that, if we cannot find a proper subset of X such that the closure of the proper subset is equal to the set of all the attributes in the relation, we know that X is a candidate key of the relation. The algo is as follows:

Algorithm : Determining X+, the Closure of X under F
X+ := X;
repeat
oldX+ := X+;
for each functional dependency Y → Z in F do
if Y is a subset of X then X+ := X+ UNION Z;
until (X+ = oldX+);
End: { Determining X+, the Closure of X under F }

Example of using the above mentioned Algorithm:
Problem: We are given a relation R(A,B,C,D,E) and the set of its functional dependencies (FDs) F = {A -> B, AC -> D, B -> E} now to find the candidate key(s) of R.

Solution: You con apply the above algorithm to each and every subset of R, but According to JBS, a *good* place to start looking for candidate keys is amongst the determinants in F.
A determinate is the LHS (Left Hand Side) of an FD. If the closure of a determinant is equivalent to R (if it is not a proper subset of R) we know that the determinant is a superkey of R and may therefore be a candidate key of R.

Using this Algo. , first we try to find whether {A} is a superkey?


X+ := {A}

oldX+:= {A}
for A -> B,
A is a subset of X+
so B is added to X+
for AC -> D,
AC is not a subset of X+
for B -> E,
B is a subset of X+
so E is added to X+
oldX+ != X+ repeat

oldX+:= {A,B,E}
for A -> B,
A is a subset of X+, B is already in X+
for AC -> D,
AC is not a subset of X+
for B -> E,
B is a subset of X+, E is already in X+
X+ = oldX+ stop
  X+ is {A}




X+ is now {A,B}

X+ is still {A,B}


X+ is now {A,B,E}




X+ is still {A,B,E}

X+ is still {A,B,E}

X+ is still {A,B,E}


The closure of {A} over F is {A,B,E} which is a proper subset of R. Therefore, {A} is not a superkey of R and cannot be a candidate key for R.

Using this Algo. , now we try to find whether {A, C} is a superkey or not?


X+ := AC

oldX+:= {A,C}
for A -> B,
A is a subset of X+
so B is added to X+
for AC -> D,
AC is a subset of X+
so D is added to X+
for B -> E,
B is a subset of X+
so E is added to X+
oldX+ != X+ repeat

oldX+:= {A,C,B,D,E}
for A -> B,
A is a subset of X+, B is already
in X+
for AC -> D,
AC is not a subset of X+
for B -> E,
B is a subset of X+, E is already
in X+
X+ = oldX+ stop

X+ is {A,C}




X+ is now {A,C,B}


X+ is now {A,C,B,D}


X+ is now {A,C,B,D,E}





X+ is still {A,C,B,D,E}

X+ is still {A,C,B,D,E}


X+ is still {A,C,B,D,E}



The closure of {A,C} over F is {A,B,C,D,E} which is not a proper subset of R. {A,C} is a superkey for R and may be a candidate key for R.

Using the same Algo. , now we try to find whether {B} is a superkey?


X+ := B

oldX+:= {B}
for A -> B,
A is a not a subset of X+
for AC -> D,
AC is not a subset of X+
for B -> E,
B is a subset of X+
so E is added to X+
oldX+ != X+ repeat

oldX+:= {B,E}
for A -> B,
A is a subset of X+
for AC -> D,
AC is not a subset of X+
for B -> E,
B is a subset of X+,
E is already in X+
X+ = oldX+ stop

X+ is {B}



X+ is still {B}

X+ is still {B}


X+ is now {B,E}




X+ is still {B,E}

X+ is still {B,E}


X+ is still {B,E}



The closure of {B} over F is {B,E} which is a proper subset of R. Therefore, {B} is not a superkey of R and cannot be a candidate key for R.

Therefore we have found a single super key {A, C} for R using this algorithm.

Connolly & Begg define a candidate key as, A superkey such that no proper subset is a superkey within the relation.
So, We require to check the proper subsets of the superkey to verify if any of these subsets are superkeys.
The proper subsets of {A,C} are: the null set, {A}, {C}
According to JBS a candidate key, which may be chosen to be a primary key, cannot be null.
We have already discovered above that {A} is not a superkey for R. So we need to consider only {C} as a possible superkey.

Using the algorithm we will try to determine whether {C} is a superkey or not?


X+ := C

oldX+:= {C}
for A -> B,
A is a not a subset of X+
for AC -> D,
AC is not a subset of X+
for B -> E,
B is not a subset of X+
oldX+ = X+ stop

X+ is {C}



X+ is still {C}

X+ is still {C}

X+ is still {C}



The closure of {C} over F is {C} which is a proper subset of R. Therefore, {C} is not a superkey of R and cannot be a candidate key for R.

We have discovered that no proper subsets of {A,C} are superkeys of R, so {A,C} is a candidate key for R.

Are there any other candidate keys for R?
We could use the above algorithm for D and E, but I am exhausted. JBS know that any attribute which is in none of the determinants in F cannot be a candidate key. If you would like to see an exhaustive application of this algorithm, you can find all the subsets of R and apply the algorithm to each subset.

We have found only one candidate key {A,C} which I must select as the primary key for R.

Therefore, the relational schema for R is R (A, C, [pk] B, D, E)

Monday, 7 March 2011

J2ee: Java Naming and Directory Interface (JNDI)

Naming and Directory Service

There was a glimpse of Naming Service in RMI. JBS told you that objects that have to be looked up by clients in a distributed system are registered in a naming service and in a naming service there is a “textual name” to “object reference” mapping. A naming service can thus be described as a feature that helps to associate a name with an object and thereby provides an interface for clients to access the object.

Like RMI other naming services are DNS (Domain Name System), which maps a textual name of a site (as, sun.java.com) to a machine’s IP Address on network. File systems also offer naming service, which maps a file name to the actual file.

A directory service is similar to a naming service, except that in addition to associating a name with the object, it also associates attributes with the object. For instance, if only authenticated users are allowed access to an object stored in a directory service, then corresponding user names and passwords are saved with objects as attributes. Access to an object is granted depending on its authentication against its user name and password.

An object in a directory service can be searched based on it’s and attributes. A directory service is arranged in a hierarchical tree-like structure, whereas a naming service is not. Thus, an organization can arrange its data better in a directory service. Every directory service is a naming service whereas every naming service need not be a directory service. The RMI registry is only a naming service and not a directory service, whereas a file system is a directory service offering naming service as well. Some of the popular directory services available in the market are Novell Directory Service (NDS) and Microsoft’s Active Directory Service.

Naming and Directory service Concepts

JBS telling you that there is a convention to be used while naming an object on the type of naming/directory service. According to the DNS naming convention, in xyz.com, xyz is an entry. Which is relative to another entry called com. Here, dot is the separator.

The process of associating a name with an object is called binding. For example, in DNS, machine names are binded with their addresses. In file system, a file named xyz.txt is a binding of the file name and the file.

A group of bindings is called a context. A context helps categorize bindings and makes searching for objects easy. For example, in a Unix file system, assume that there is a directory called Sample Directory under root, with file name file1, file2 and file3. Here, Sample Directory is a context consisting three bindings. So, file1 would be named “/Sample Directory/file1”.

A context can have another within it. The embedded context i called a subcontext. A subcontext is valid only in directory services and not in naming services, as naming services are not arranged in a hierarchical tree-like structure. In terms of file system, a sub-directory is called a subcontext. In the Unix system, if Sample Directory has a sub-directory called Sub Sample Directory, which in turn has a file, example1, the name for example1 relative to the root would be “/Sample Directory/Sub Sample Directory/example1”. In DNS, domains com, edu, etc are contexts created to categorize websites, whereas in “mail.xyz.com”, domain com is a context, domain xyz is a subcontext of com and xyz has a binding where the name mail which is mapped to the IP address of the machine.

A namespace is a set of all the names in naming/directory service.

The name of the object can be a composite name spanning multiple naming/directory services. A composite name can have several components, each of which might belong to a different service.

A compound name is a name that belongs to a naming or directory service. A compound name in a naming service can have only components. For example, a compound name in a DNS service would look like www.ibm.com. However, a compound name in a directory service can have many components because of its hierarchical structure. For example, a compound name in a Unix file system, which is a directory, would look like “/Sample Directory/Sample File”. Compound names are composed according to the naming conversion of that service.

If a component of a name cannot be divided future then it is an atomic name.

Different Naming and Directory Services

Now JBS will tell you some of the popular naming and directory services.

  1. RMI Registry: The RMI registry is a naming service that does not provide directory features and follows a flat system (A flat system is one that does not have a tree like structure). The concept of a sub context is not applicable to the RMI registry. Therefore, a name in a RMI registry can have only one component.
  2. COS Naming: COS Naming is a directory service used by CORBA programs for binding CORBA objects. Here, a compound name can have more than one component.
  3. Network Information Service (NIS): NIS is a directory service from Sun Microsystems, which was earlier called Sub Yellow Pages. It is used to store, information that has to be shared across the network. Information such as user name and password are stored in it to enable clients to login from any machine in the network that has a NIS client running.
  4. IBM WAS: IBM WAS includes a directory service, which offers shared access to Java components. Complex search operations on directory objects are not supported.
  5. Service Using Lightweight Directory Access Protocol (LDAP): LDAP is a protocol that was accepted by some directory services in the market. Services following the LDAP are all accessed in the same way. They use a naming convention where the separator between each component in a name is comma. For example, CN=Printer, OU=Network services, O=headquarters is a name where CN=Pinter is an entry relative to OU=Network service, which in turn is relative to another entry O=Headquarters, In a LDAP name, each component is a name-value pair. Moreover, the name is read from right to left. So, here O=Headquarters is a context having a subcontext OU=Network series. The subcontext OU=Network services has a binding with the name CN=Printer.
Introduction to Java Naming and Directory Interface

JNDI was introduced to provide programmers with a common interface to access different naming and directory services. JNDI is similar to JDBC, which provides a common technique to access different databases. A java programmer making JDBC calls to a database would do so in a standard vendor-independent manner. These calls are same irrespective of the database used. These calls are then passed on to a driver (specific to the database being used), which translates them into calls that can be understood by the database and passes them to the database. The results are sent by the database in a database-specific from to the driver, which are then translated by the driver into a standard form and returned to the Java program.

Applying the same concept to JNDI, a java program can make a JNDI call to access a naming or directory service to retrieve an object registered. The calls are transferred to a service provider that is associated with the naming or directory service being accessed. The service provider knows how to translate the JNDI call to vendor-specific call. The service provider passes the object retrieved from the underlying naming/directory service to the Java program. This object can be written in any language, but when given to the Java program, it will become a Java object.

JNDI Architecture

The JNDI architecture consists of an API that is used by Java applications to access naming and directory services. It also consists of a Service Provider Interface (SPI) implemented by service providers so that they can make available the service they support to the Java application. The following figure illustrates the JNDI architecture.









Going back to JDBC, if a Java program has to access a database using JDBC, then the driver corresponding to the database should be available. Similarly, if a java program has to access a naming/directory service using JNDI, the corresponding service provider for that naming/directory service should be available.

The JNDI is included in java 2 SDK V1.3 and later releases. It also includes service provider for LDAP, COS naming and RMI registry. Thus the corresponding naming/directory service can be accessed through the APIs. To use any other naming/directory service, the corresponding service provider has to be a downloaded from the JNDI website.

Application programs, which need to work with naming and directory services, can use the javax.naming and javax.naming.directory packages. Service providers who wish to provide their implementations so that their corresponding naming/directory service is available to application programs using JNDI can use the javax.naming.spi package.

Environment Properties in details

We know that while trying to create an initialcontext to start working with a naming/directory service, the application using the service has to specify certain properties called environment properties. JNDI defines some standard environment properties, which however, need not apply to all service providers. However, If applicable, the implementation should conform to JNDI specifications. Some service providers have environment properties specific only to their services.

In the above-mentioned examples showing the usage of JNDI to access file system, we have specified two standard environment properties. Let us discuss them now with JBS.

The first standard property is the initial context factory. To create the initialcontext, we have to specify a property called initial context factory. The value for this property would be the fully qualified name of the factory class that will create the initial context. The factory class is a class that knows how to create the initialcontext for the naming/directory service that it is associated with. By creating the initalcontext, we specify which service provider is to be used. For example, for the File system, the fully qualified name of the factory class is com.sun.jndi.fscontext.RefFSContextFactory.

Now there has to be some way of specifying the name of the property. The Context interface defines a constant INITIAL_CONTEXT_FACTORY. This constant has a string value java.naming.factory.initial. This is the name of the property. In a code, both can be used interchangeable, that is, either Context.INITIAL_CONTEXT.FACTORY or the string value java.naming.factory.initial can be used to specify the name of the property. Therefore, in the code showing the usage of JNDI to access file system, the property is Context.INITIAL_CONTEXT_FACTORY (or can also be given as the string java.naming.factory.initial) and the value for the property is com.sun.jndi.fscontext.RefFSContextFactory.

The second standard property in the code defined by the constant PROVIDER_URL specifies the location of the service and the starting point for the initialcontext. The string value associated with this constant is java.naming.provider.url. The value given for this property is in the form of a URL. For example, in the code showing the usage of JNDI to access file system, the protocol specified is file and the starting point is c:\\.

Similarly, for each environment property, the Context interface defines constants that have an associated string value. When specifying the property, either of them can be used as the name for the property. But remember that the properties are always to be specified as a name=value pair, i.e., the name of the property (given either as a constant of as a string corresponding to the constant) and the associated value.

In the above-mentioned examples, the environment properties are specified through a Hashtable. There are also other ways of specifying them.

An application resource file is one that is given the name jndi.properties. This file helps a JNDI program to acquire environment properties that it needs. This file has the environment properties, needed by that JNDI program, specified as key-value pairs. The application resource file should be in the classpath for JNDI program to find it. For example, if the file system is the service being accessed in a JNDI program, then the jndi.properties file has the following content.

java.naming.factory.initial = com.sun.jndi.fscontext.RefFSContextFactory

java.naing.propider.url = file:c:\\

The program accessing the file system would create an initialcontext using the default constructor as follows:

Context contx=new.InitialContext ();

When trying to create the intialcontext, since Hashtable is not passed to the constructor, the JNDI automatically looks for the jndi.properties file and picks up the environment properties. Thus, there is no need for manually coding the environment properties within the program.

DataSource

To write a traditional JDBC client program using the core JDBC API, perform the following steps:

  1. Load the required driver class.
  2. Get a connection to the database.
  3. Execute SQL queries.
  4. Close the connection.

The above architecture has the following drawbacks:

  1. The driver name, URL, etc. are embedded in the program. Thus, changing the database is very inconvenient.
  2. The client program is responsible for loading the driver and thus, the client program should be aware of the driver name.
  3. When a connection is established, a lot of resources are used.
  4. The connection, which is created with so much effort, can be used only once and cannot be reuse.

JDBC 2.0 Optional Package API overcomes the above-mentioned problems by supporting a concept called DataSource. DataSources offer the following advantages while writing a program to access databases:

  1. The client program need not remember the driver name, URL, etc.
  2. Connection can be reused through connection pooling
  3. Code portability and maintenance is improved.

First, a DataSource object is created with the details required to establish a connection to a database. This object is then bound to a textual name in a JNDI service. Using JNDI API, the client program can contact the JNDI service and lookup the DataSource object by specifying its name. From this DataSource object, a connection to the database is acquired. Thereafter, the operations are the same as any traditional JDBC program. The advantage here is all the details required to create a connection is supplied at the time of creation of a DataSource. The client program need not be aware of any of the connection details. The DataSource object can be obtained from the JNDI service and then a connection can be acquired from it. The only detail the client program needs to know is the JNDI name of the DataSource.

Creating and Using DataSources with JBS

Application server such as WAS and WebLogic support DataSources. These application servers provide a GUI through which information required to create a DataSource object (such as driver-name, URL for the database, database, database) can be supplied to the application server by the programmer, before writing the code to access the DataSource object. The name to be mapped with the DataSoruce object when it is bound in the JNDI service is also given by the programmer along with the above mentioned details. The application server itself usually has a JNDI service.

The JDBC 2.0 Optional Package API provides the javax.sqp.DataSource interface. When the server is started, it creates an object of a class that implements javax.sql.DataSource with the information entered earlier by the programmer through the GUI. The sever then binds the DataSource object with its JNDI service. To establish a connection with the databse, which the DataSource refers to, client programs use JNDI API to first lookup the DataSource object by its name. Once this object is found, a connection to the database is established.

The steps to create a DataSource object and access a database are as follows

  1. Create an initialcontext for the JNDI service. The environment properties supplied would be relevant to the application server whose JNDI service is being used.
  2. Perform a lookup through the lookup() method using the initialcontext. The JNDI name of the DataSource object is supplied to the lookup() method.
  3. The lookup() method returns an object of type java.lang.Object. Typecast the object to javax.sql.DataSource.
  4. The getConnection() method of java.sql.DataSource interface is invoked on the DataSource object, which returns a java.sql.Connection object. However, the internal behavior of this object is different from the java.sql.Connection object that is normally used in JDBC program.

Once the Connection object is acquired, the code for the rest of the program is similar to that of any other JDBC program. One main difference is that while java.sql.DriverManager class is used in the code using normal JDBC to acquire a connection, in the code using DataSource, javax.sql.DataSource is used. Moreover, now here does the client program specify the driver name or load the driver. Assume there is a dataSource registered in the name jdbc/sampledatasource in a JNDI service.

Connection Pooling

One main advantage of using DataSource is that they support connection pooling. A connection pool is a cache of persistent database connections maintained in the memory. Connection pooling allows connections to be reused. If an application needs a database connection, it would contact the pool and acquire a connection. Immediately after completing the SQL operations, it returns the connection to the pool. Later another application, or the same application, can contact the pool for a connection object. The recently used connection object or another from the pool will be given to fulfill the demand.

Thus, the connections are not broken after an application stops using them. Instead they are reused by the same application or by other applications, which improves performance. The pool actually maintains java.sql.Connection objects. However, the implementation of these Connection objects is different from that of the Connection objects used in a normal JDBC program.

The questions arises as to why should there be a pool of connections? Should not just one sufficient? There could be several applications simultaneously in need of a database connection to the same database. So, when one application is using a connection from the pool, another application requiring a connection object should not be made to wait. A free connection from the pool can be given to it.

A connection pool usually has a maximum limit and holds a certain number of connections only. If the demand crosses this limit, then the applications are made to wait until one of the connections is released back to the pool. The application server in which the DataSource is created and bound is responsible for the creation and maintenance of the pool.

Not all servers support connection pooling. Under such circumstance, when an application acquires a DataSource object and requests a Connection object, the DataSource creates a Connection object and gives it to the application. However, this connection cannot be reused, as the server does not support connection pool.

An application does a lookup and acquires a DataSource object. When the getConnection() method is invoked on the DataSource object. The connection pool is contacted; a connection object from this pool is picked and returned to the application. The application can use this connection object and when it does not require it any more it invokes the close() method of the Connection object.

Thus the steps it use DataSoruce would be:

  1. Enter information such as driver name, URL for the database, database name, and minimum and maximum limit for connection pool through a GUI provided by the application, to create a DataSoruce.
  2. Start the server.
  3. DataSource gets bound to the JNDI service of the application server.
  4. If the server supports connection pooling, then it creates a connection pool with connection object, each of which maintain a connection to the database.
  5. An application that needs a connection to the database, requests for a DataSource object associated with that database.
  6. The getConnection() method is invoked on the DataSource.
  7. If the server supports a connection pool, the DataSource contacts the pool manager and the pool manager gives a Connection object. Otherwise the DataSource Object itself creates a Connection object and returns it.
  8. Application calls close() method on the Connection object.
  9. The Connection object is returned to the connection pool, if there is one. Otherwise the connection is closed.

When creating a DataSource through the GUI, supported by an application server, the minimum and maximum number of live connections to be maintained in a connection pool must also be specified. When be server is started and the DataSource object is bound to its JNDI service, a connection pool is established corresponding to the DataSource. There is usually a pool manager object responsible for maintaining the pool. The pool will have at least the minimum number of Connection objects maintain a persistent connection with the database to which the DataSource is associated.