Thursday 30 March 2017

C++ Reference Parameters Versus Java Reference Parameters & Converting C++ Abstract Classes into Java Interfaces - Java Tutorials

C++ Reference Parameters Versus Java Reference Parameters

In the preceding section, you saw an example of a C++ program that used a pointer parameter. In Java, this became a reference parameter. Of course, C++ also supports reference parameters. As mentioned, most pointer parameters found in C++ code are simply holdovers from C. Nearly all new C++ code will use reference parameters when a function needs access to the argument, itself. (In essence, pointer parameters, although still common, are actually anachronisms in most C++ code.) Since both Java and C++ support reference parameters, you might think that the conversion of a C++ function that uses reference parameters to a Java method would involve few changes. Unfortunately, this is not always the case. To understand why, let’s convert the following C++ program, which swaps the contents of two Coord objects using reference parameters:

  // Swap coordinates -- C++ version.
  #include <iostream>
  using namespace std;

  class Coord {
  public:
    int x;
    int y;
  };

  // Swap contents of two Coord objects.
  void swap(Coord &a, Coord &b) {
    Coord temp;

    // swap contents of objects
    temp = a;
    a = b;
    b = temp;
  }
  int main()
  {
    Coord ob1, ob2;
    
    ob1.x = 10;
    ob1.y = 20;

    ob2.x = 88;
    ob2.y = 99;

    cout << "Original values:\n";
    cout << "ob1: " << ob1.x << ", " << ob1.y << "\n";
    cout << "ob2: " << ob2.x << ", " << ob2.y << "\n";
    cout << "\n";
    swap(ob1, ob2);

    cout << "Swapped values:\n";
    cout << "ob1: " << ob1.x << ", " << ob1.y << "\n";
    cout << "ob2: " << ob2.x << ", " << ob2.y << "\n";

    return 0;
  }

Following is the output produced by this program. As you can see, the contents of ob1 and ob2 have been exchanged:

  Original values:
  ob1: 10, 20
  ob2: 88, 99

  Swapped values:
  ob1: 88, 99
  ob2: 10, 20

In Java, all objects are accessed via an object reference variable. Thus, when an object is passed to a method, only its reference is passed. This means that all objects are automatically passed by reference to a Java method. Without thinking any deeper about what is actually occurring, someone might initially try the following (incorrect) conversion of the preceding program:

  // Swap program incorrectly converted to Java.
  class Coord {
    int x;
    int y;
  };

  class SwapDemo {
    static void swap(Coord a, Coord b) {
      Coord temp = new Coord();

      // this won't swap contents of a and b!
      temp = a;
      a = b;
      b = temp;
    }

    public static void main(String args[]) {
      Coord ob1 = new Coord();
      Coord ob2 = new Coord();

      ob1.x = 10;
      ob1.y = 20;

      ob2.x = 88;
      ob2.y = 99;

      System.out.println("Original values:");
      System.out.println("ob1: " +
                         ob1.x + ", " + ob1.y);
      System.out.println("ob2: " +
                         ob2.x + ", " + ob2.y + "\n");

      swap(ob1, ob2);

      System.out.println("Swapped values:");
      System.out.println("ob1: " +
                         ob1.x + ", " + ob1.y);
      System.out.println("ob2: " +
                         ob2.x + ", " + ob2.y + "\n");
    }
  }

The output produced by this incorrect program is shown here:

  Original values:
  ob1: 10, 20
  ob2: 88, 99

  Swapped values:
  ob1: 10, 20
  ob2: 88, 99

As you can see, the values of ob1 and ob2 in main( ) have not been exchanged! Although a bit counterintuitive at first, the reason is actually obvious, once you understand precisely what happens when an object reference is passed to a method. Java passes all arguments to methods using call-by-value. This means that a copy of the argument is made, and what occurs to the copy inside the method has no effect on the argument used to call the method. However, this situation is blurred a bit in the case of object references.

When an object reference is passed to a method, a copy of the reference variable is made, as just explained. This means that the parameter inside the method will refer to the same object as does the reference variable used as an argument outside the method. Therefore, operations on the object through the parameter will affect the object referred to by the argument (since they are one and the same). But operations on the reference parameter, itself, affect only that parameter. Thus, when the preceding program attempts to swap the objects by exchanging the objects pointed to by a and b, all that is happening is that the parameters (that is, the copies of the arguments) are exchanging what they are referring to, but this does not alter what ob1 and ob2 refer to back in main( ).

To fix the program, swap( ) needs to be rewritten so that the contents of the objects are exchanged, not what the parameters refer to. Here is the corrected version of swap( ):

  // Corrected version of swap().
  static void swap(Coord a, Coord b) {
    Coord temp = new Coord();

    // swap contents of objects
    temp.x = a.x;
    temp.y = a.y;
    a.x = b.x;
    a.y = b.y;
    b.x = temp.x;
    b.y = temp.y;
  }

If you substitute this version of swap( ) into the preceding program, the correct results will be achieved.




Converting C++ Abstract Classes into Java Interfaces

One of the most innovative aspects of Java is the interface. As explained earlier in this book, an interface specifies the form of its various methods without specifying any implementation details. Each class that implements an interface does so by creating the actual methods declared by the interface. Thus, in Java an interface is the means by which you can define the general form of a class while ensuring that all specific versions of the class conform to the same set of rules. The interface is one of the ways that Java provides support for polymorphism.

In C++, there is no direct parallel to the interface. Instead, in C++, if you wish to define the form of a class without defining implementation details, you must do so by using an abstract class. Abstract classes in C++ are similar to abstract classes in Java: they do not contain a full set of implementation details. In C++, an abstract class contains at least one pure virtual function. A pure virtual function defines no implementation; it only defines the function prototype. Thus, a pure virtual function in C++ is essentially the same as an abstract method in Java. In C++, abstract classes serve a function similar to interfaces in Java. For this reason, they are one of the items that you will want to watch for when converting code to Java. While not all C++ abstract classes can be converted into Java interfaces, many can. Let’s look at two examples.

Here is a short C++ program that uses an abstract class called IntList to define the form of an integer list. An implementation of this class is created by IntArray, which uses an array to implement a list of integers.

  // A C++-style abstract class and its implementation.
  #include <iostream>
  #include <cstdlib>
  using namespace std;

  // An abstract class that defines the form of an integer list.
  class IntList {
  public:
    virtual int getNext() = 0; // pure virtual functions
    virtual void putOnList(int i) = 0;
  };

  // Create an implementation of an integer list.
  class IntArray : public IntList {
    int storage[100];
    int putIndex, getIndex;
  public:
    IntArray() {
      putIndex = 0;
      getIndex = 0;
    }

    // Return next integer in list.
    int getNext() {
      if(getIndex >= 100) {
        cout << "List Underflow";
        exit(1);
      }
      getIndex++;
      return storage[getIndex-1];
    }

    // Put an integer on the list.
    void putOnList(int i) {
      if(putIndex < 100) {
        storage[putIndex] = i;
        putIndex++;
      }
      else {
        cout << "List Overflow";
        exit(1);
      }
    }
  };

  int main()
  {
    IntArray nums;
    int i;

    for(i=0; i<10; i++) nums.putOnList(i);

    for(i=0; i<10; i++)
      cout << nums.getNext() << endl;

    return 0;
  }

In this program, the abstract class IntList defines only the form of an integer list. It contains only pure virtual functions and does not declare any data. For these reasons, it can be made into an interface when the program is converted into Java, as shown here:

  // Here, IntList is made into an interface which IntArray
                                                   implements.
  // Define interface for an integer list.
  interface IntListIF {
    int getNext();
    void putOnList(int i);
  }

  // Create an implementation of an integer list.
  class IntArray implements IntListIF {
    private int storage[];
    private int putIndex, getIndex;

    IntArray() {
      storage = new int[100];
      putIndex = 0;
      getIndex = 0;
    }

    // Create an implementation of an integer list.
    public int getNext() {
      if(getIndex >= 100) {
        System.out.println("List Underflow");
        System.exit(1);
      }
      getIndex++;
      return storage[getIndex-1];
    }

    // Put an integer on the list.
    public void putOnList(int i) {
      if(putIndex < 100) {
        storage[putIndex] = i;
        putIndex++;
      }
      else {
        System.out.println("List Overflow");
        System.exit(1);
      }
    }
  }

  class ListDemo {
    public static void main(String args[]) {
      IntArray nums = new IntArray();
      int i;

      for(i=0; i<10; i++) nums.putOnList(i);

      for(i=0; i<10; i++)
        System.out.println(nums.getNext());
    }
  }

As you can see, there is nearly a one-to-one correspondence between the C++ abstract class IntList and the Java interface IntListIF. It is possible to convert IntList into IntListIF because it contained only pure virtual functions. This is the key. If IntList had contained any data or function implementations, then it would not have qualified for conversion into an interface.

When you convert or adapt C++ code into Java, look for examples of abstract classes that contain only pure virtual functions. These are prime candidates for conversion to Java interfaces. But don’t overlook abstract C++ classes that contain a small number of implemented functions or data. It is possible that these items don’t really belong in the abstract class to begin with and should be defined by individual implementations. Since C++ does not define an interface construct, there was no reason
for C++ programmers to think in terms of one.

Sometimes a concrete member is contained in an otherwise abstract class simply for expedience—not because it is the most logical place for it. For example, consider the following abstract C++ class:

  // An abstract C++ class.
  class SomeClass {
    bool isOK;
  public:
    virtual int f1() = 0;
    virtual void f2(int i) = 0;
    virtual double f3() = 0;
    virtual int f4(int a, char ch) = 0;
  };

The only reason that this class cannot be made into a Java interface is the existence of isOK. Presumably, isOK is used to indicate some status associated with the class. However, if you think about it, there really is no reason for isOK to be defined as a variable. Instead, you could specify a method called isOK( ) that returns the status. In this approach, isOK( ) will be defined, along with the other methods, by any implementing class. Thus, you could convert the preceding C++ abstract class into the following Java interface:

  interface SomeClass {
    int f1();
    void f2(int i);
    double f3();
    int f4(int a, char ch);
    boolean isOK();
  }
Many abstract classes in C++ can—and should—be converted into interfaces when you move code to Java. In doing so, you will probably find that it clarifies the structure of the class hierarchy.

The Differences Between C++ and Java & Eliminating Pointers - Java Tutorials

The Differences Between C++ and Java

Before we look at specific situations, let’s review the basic differences between C++ and Java. The differences fall into three categories:
  • C++ features not supported by Java
  • Features unique to Java
  • Shared features which differ between C++ and Java

Each is examined here.


What Java Has Removed from C++

There are a number of C++ features that Java does not support. In some cases, a specific C++ feature simply didn’t relate to the Java environment. In other cases, the designers of Java eliminated some of the duplication of features that exists in C++. In still other instances, a feature of C++ is not supported by Java because it was deemed too dangerous for Internet applets.

Perhaps the single biggest difference between Java and C++ is that Java does not support pointers. As a C++ programmer you know that the pointer is one of C++’s most powerful and important language features. It is also one of its most dangerous when used improperly. Pointers don’t exist in Java for two reasons:
  • Pointers are inherently insecure. For example, using a C++-style pointer, it is possible to gain access to memory addresses outside a program’s code and data. A malicious program could make use of this fact to damage the system, perform unauthorized accesses (such as obtaining passwords), or otherwise violate security restrictions.
  • Even if pointers could be restricted to the confines of the Java run-time system (which is theoretically possible), the designers of Java believed that they were inherently troublesome. 
Since pointers don’t exist in Java, neither does the -> operator.

Here are a few more of the most important “omissions”:
  • Java does not include structures or unions. These were felt to be redundant since the class encompasses them.
  • Java does not support operator overloading. Operator overloading is sometimes a source of ambiguity in a C++ program, and the Java design team felt that it causes more trouble than benefit.
  • Java does not include a preprocessor nor does it support the preprocessor directives. The preprocessor plays a less important role in C++ than it does in C. The designers of Java felt that it was time to eliminate it entirely.
  • Java does not perform any automatic type conversions that result in a loss of precision. For example, a conversion from long integer to integer must be explicitly cast.
  • All the code in a Java program is encapsulated within one or more classes. Therefore, Java does not have what you normally think of as global variables or global functions.
  • Java does not allow default arguments. In C++, you may specify a value that a parameter will have when there is no argument corresponding to that parameter when the function is invoked. This is not allowed in Java.
  • Java does not support the inheritance of multiple superclasses by a subclass.
  • Although Java supports constructors, it does not have destructors. It does, however, add the finalize( ) function.
  • Java does not support typedef.
  • It is not possible to declare unsigned integers in Java.
  • Java does not allow the goto.
  • Java does not have the delete operator.
  • The << and >> in Java are not overloaded for I/O operations.
  • In Java, objects are passed by reference only. In C++, objects may be passed by value or by reference.


New Features Added by Java

There are a number of features in Java that have no equivalent in C++. Perhaps the three most important are multithreading, packages, and interfaces, but there are several others that enrich the Java programming environment as well.
  • As explained earlier, multithreading allows two or more pieces of the same program to execute concurrently. Further, this approach to concurrence is supported at the language level. There is no parallel for this in C++. If you need to multithread a C++ program, you will need to do so manually, using operating system functions. While both methods allow for concurrent execution of two or more threads, Java’s approach is cleaner and easier to use.
  • There is no feature in C++ that directly corresponds to a Java package. The closest similarity is a set of library functions that use a common header file. However, constructing and using a library in C++ is completely different from constructing and using a package in Java.
  • The Java interface is somewhat similar to a C++ abstract class. (An abstract class in C++ is a class that contains at least one pure virtual function.) For example, it is impossible to create an instance of a C++ abstract class or a Java interface. Both are used to specify a consistent interface that subclasses will implement. The main difference is that an interface more cleanly represents this concept.
  • Java has a streamlined approach to memory allocation. Like C++, it supports the new keyword. However, it does not have delete. Instead, when the last reference to an object is destroyed, the object, itself, is automatically deleted the next time that garbage collection occurs.
  • Java “removes” the C++ standard library, replacing it with its own set of API classes. While there is substantial functional similarity, there are significant differences in the names and parameters. Also, since all of the Java API library is object-oriented, and only a portion of the C++ library is, there will be differences in the way library routines are invoked.
  • The break and continue statements have been enhanced in Java to accept labels as targets.
  • The char type in Java declares 16-bit-wide Unicode characters. This makes them similar to C++’s wchar_t type. The use of Unicode helps ensure portability.
  • Java adds the >>> operator, which performs an unsigned right shift.
  • In addition to supporting single-line and multiline comments, Java adds a third comment form: the documentation comment. Documentation comments begin with a /** and end with a */.
  • Java contains a built-in string type called String. String is somewhat similar to the standard string class type provided by C++. Of course, in C++ string is only available if you include its class declarations in your program. It is not a built-in type.


Features That Differ

There are some features common to both C++ and Java that each language handles a bit differently:
  • While both C++ and Java support a Boolean data type, Java does not implement true and false in the same way as C++. In C++, true is any nonzero value. False is zero. In Java, true and false are predefined literals, and these are the only values that a boolean expression may have. While C++ also defines true and false, which may be assigned to a bool variable, C++ automatically converts nonzero values into true and zero values into false. This does not occur in Java.
  • When you create a C++ class, the access specifiers apply to groups of statements. In Java, access specifiers apply only to the declarations that they immediately precede.
  • C++ supports exception handling that is fairly similar to Java’s. However, in C++ there is no requirement that a thrown exception be caught.

With these additions, deletions, and differences as a backdrop, the rest of this chapter will look closely at a few of the key issues that you must deal with when converting code from C++ to Java.




Eliminating Pointers

When you convert a C++ program into Java, perhaps the greatest number of changes will be caused by pointers. Most C++ code is heavily dependent upon pointers for its operation. You can’t program anything very significant in C++ without using a pointer. There are four general categories of pointer usage that you will encounter in C++ code:
  • As parameters to functions. Although C++ supports the reference parameter, there is a large base of legacy code that was originally written in C. C does not support reference parameters. In C, if a function needs to change the value of an argument, it is necessary to explicitly pass a pointer to that argument. Therefore, it is still common to find pointer parameters used in C++ code that was originally ported from C. Also, in some cases the same function library will need to be shared by both C and C++ code, which prevents the use of reference parameters. Additionally, many of the standard library functions supported by C++ are holdovers from C. When one of these C-based functions requires the address f an argument, a pointer to the argument is used. Inside the function, the argument is then accessed through its pointer.
  • To provide a more efficient means of implementing certain constructs—especially array indexing. For example, it is often more efficient to sequentially move through an array using a pointer rather than an array index. While modern compilers implement highly efficient optimizations, pointers can still provide a significant performance boost. Thus, the use of pointers to access arrays is ubiquitous in C++ code.
  • To support memory allocation. In C++, when you allocate memory, an address (that is, a pointer) to that memory is returned. This address must be assigned to a pointer variable. Once this has been done, the pointer can point to any part of the allocated memory—or anywhere else, for that matter—by means of pointer arithmetic. In Java, when an object is allocated by new, a reference to the object is returned. This reference must be assigned to a reference variable of a compatible type. While Java reference variables do implicitly point to the object that was allocated by the new operator, they cannot be manipulated in the same way as C++ pointers. And they cannot point to memory outside of the Java run-time context.
  • To provide access to any arbitrary machine address, possibly to call a ROM routine or to read/write directly to memory. Since Java purposely disallows such actions, this use of pointers has no direct parallel. If you are writing applications, not applets, you can always use Java’s native capabilities (described in Part One) to gain access to native code routines that would be allowed access to such system resources. 


Let’s look at two situations in which pointer-based C++ code is converted to Java.


Converting Pointer Parameters

For the most part, it is quite easy to convert a C++ function that uses pointer parameters into its equivalent Java method. Since Java passes all objects by reference, sometimes the conversion simply requires the removal of C++’s pointer operators. For example, consider this C++ program that reverses the signs of a Coord object, which stores a pair of Cartesian coordinates. The function reverseSign( ) is passed a pointer to the Coord object that will be reversed. As you can see, C++’s *, &, and -> pointer operators are used to perform the operation.

  // Reverse the signs of a coordinate - C++ version.
  #include <iostream>
  using namespace std;

  class Coord {
  public:
    int x;
    int y;
  };

  // Reverse the sign of the coordinates.
  void reverseSign(Coord *ob) {
    ob->x = -ob->x;
    ob->y = -ob->y;
  }

  int main()
  {
    Coord ob;

    ob.x = 10;
    ob.y = 20;

    cout << "Original values for ob: ";
    cout << ob.x << ", " << ob.y << "\n";

    reverseSign(&ob);

    cout << "Sign reversed values for ob: ";
    cout << ob.x << ", " << ob.y << "\n";

    return 0;
  }

This program can be recoded into the following Java version. As you can see, most of the conversion involves the deletion of the C++ pointer operators. Since Java passes objects by reference, changes to the parameter automatically affect the argument.

  // Reverse the signs of a coordinate - Java version.
  class Coord {
    int x;
    int y;
  };

  class DropPointers {
    // Reverse the sign of the coordinates.
    static void reverseCoord(Coord ob) {
      ob.x = -ob.x;
      ob.y = -ob.y;
    }
    public static void main(String args[]) {
      Coord ob = new Coord();

      ob.x = 10;
      ob.y = 20;

      System.out.println("Original values for ob: " +
        ob.x + ", " + ob.y);

      reverseCoord(ob);

      System.out.println("Sign reversed values for ob: " +
        ob.x + ", " + ob.y);
    }
  }

The output from both of these programs is the same and is shown here:

  Original values for ob: 10, 20
  Sign reversed values for ob: -10, -20


Converting Pointers that Operate on Arrays

Conceptually, converting C++-style pointer-based array accessing into the equivalent Java-compatible array indexing is straightforward—simply substitute the appropriate array-indexing statements. However, in practice this may require some thought. Pointer-based array accessing can be a bit difficult to follow, because the normal C++ coding style encourages rather dense, complex expressions. For example, this short C++ program copies the contents of one array to another. It uses 0 to mark the end of the arrays. Pay special attention to the pointer expressions. Even in this simple example, if you did not know that this program copied the contents of nums to copy (and later displayed the arrays), it would require some careful thought before you were completely sure that you knew what the code was doing.

  // Copy an array in C++ using pointers.
  #include <iostream>
  using namespace std;

  int main()
  {
    int nums[] = {10, 12, 24, 45, 23, 19, 44,
                  88, 99, 65, 76, 12, 89, 0};
    int copy[20];

    int *p1, *p2; // integer pointers

    // copy array
    p1 = nums; // p1 points to start of nums array
    p2 = copy;
    while(*p1) *p2++ = *p1++;
    *p2 = 0; // terminate copy with zero

    // Display contents of each array.
    cout << "Here is the original array:\n";
    p1 = nums;
    while(*p1) cout << *p1++ << " ";
    cout << endl;

    cout << "Here is the copy:\n";
    p1 = copy;
    while(*p1) cout << *p1++ << " ";
    cout << endl;

    return 0;
  }

Even though it is quite simple for C++ code, at first glance the line

  while(*p1) *p2++ = *p1++;

still requires a moment of thought to decipher its exact operation. One of the advantages of Java is that it does not encourage the creation of such expressions in the first place. Here is the Java version of the program. As you can see, its purpose and effects are transparent.

  // Array copy without pointers using Java.
  class CopyArray {
    public static void main(String args[]) {
      int nums[] = {10, 12, 24, 45, 23, 19, 44,
                    88, 99, 65, 76, 12, 89, 0};
      int copy[] = new int[14];
      int i;

      // copy array
      for(i=0; nums[i]!=0; i++)
        copy[i] = nums[i];
      nums[i] = 0; // terminate copy with zero

      // Display contents of each array.
      System.out.println("Here is the original array:");
      for(i=0; nums[i]!=0; i++)
        System.out.print(nums[i] + " ");
      System.out.println();

      System.out.println("Here is the copy:");
      for(i=0; nums[i]!=0; i++)
        System.out.print(copy[i] + " ");
      System.out.println();
    }
  }

Both versions of the program produce the following results:

  Here is the original array:
  10 12 24 45 23 19 44 88 99 65 76 12 89
  Here is the copy:
  10 12 24 45 23 19 44 88 99 65 76 12 89

Much C++ code is sprinkled with obscure, difficult to understand pointer expressions. While these expressions do tend to increase speed of execution, they are one of the most troubling issues associated with the maintenance of C++ programs. They will also present difficulty when you convert the code to Java. When you are confronted with a complex pointer expression, it is sometimes useful to begin by breaking it into its subexpressions so that its exact operation becomes clear.

Handling HTTP Requests and Responses, Using Cookies & Session Tracking - Java Tutorials

Handling HTTP Requests and Responses

The HttpServlet class provides specialized methods that handle the various types of HTTP requests. A servlet developer typically overrides one of these methods. These methods are doDelete( ), doGet( ), doHead( ), doOptions( ), doPost( ), doPut( ), and doTrace( ). A complete description of the different types of HTTP requests is beyond the scope of this book. However, the GET and POST requests are commonly used when handling form input. Therefore, this section presents examples of these cases.

Handling HTTP GET Requests

Here we will develop a servlet that handles an HTTP GET request. The servlet is invoked when a form on a Web page is submitted. The example contains two files. A Web page is defined in ColorGet.htm and a servlet is defined in ColorGetServlet.java. The HTML source code for ColorGet.htm is shown in the following listing. It defines a form that contains a select element and a submit button. Notice that the action parameter of the form tag specifies a URL. The URL identifies a servlet to process the HTTP GET request.

  <html>
  <body>
  <center>
  <form name="Form1"
    action="http://localhost:8080/examples/servlet/ColorGetServlet">
  <B>Color:</B>
  <select name="color" size="1">
  <option value="Red">Red</option>
  <option value="Green">Green</option>
  <option value="Blue">Blue</option>
  </select>
  <br><br>
  <input type=submit value="Submit">
  </form>
  </body>
  </html>

The source code for ColorGetServlet.java is shown in the following listing. The doGet( ) method is overridden to process any HTTP GET requests that are sent to this servlet. It uses the getParameter( ) method of HttpServletRequest to obtain the selection that was made by the user. A response is then formulated.

  import java.io.*;
  import javax.servlet.*;
  import javax.servlet.http.*;

  public class ColorGetServlet extends HttpServlet {

    public void doGet(HttpServletRequest request,
      HttpServletResponse response)
    throws ServletException, IOException {

      String color = request.getParameter("color");
      response.setContentType("text/html");
      PrintWriter pw = response.getWriter();
      pw.println("<B>The selected color is: ");
      pw.println(color);
      pw.close();
    }
  }

Compile the servlet and perform these steps to test this example:
  1. Start Tomcat, if it is not already running.
  2. Display the Web page in a browser.
  3. Select a color.
  4. Submit the Web page.

After completing these steps, the browser will display the response that is dynamically generated by the servlet.

One other point: Parameters for an HTTP GET request are included as part of the URL that is sent to the Web server. Assume that the user selects the red option and submits the form. The URL sent from the browser to the server is

  http://localhost:8080/examples/servlet/ColorGetServlet?color=Red

The characters to the right of the question mark are known as the query string.

Handling HTTP POST Requests
Here we will develop a servlet that handles an HTTP POST request. The servlet is invoked when a form on a Web page is submitted. The example contains two files. A Web page is defined in ColorPost.htm and a servlet is defined in ColorPostServlet.java.

The HTML source code for ColorPost.htm is shown in the following listing. It is identical to ColorGet.htm except that the method parameter for the form tag explicitly specifies that the POST method should be used, and the action parameter for the form tag specifies a different servlet.

 <html>
 <body>
 <center>
 <form name="Form1"
   method="post"
   action="http://localhost:8080/examples/servlet/ColorPostServlet">
 <B>Color:</B>
 <select name="color" size="1">
 <option value="Red">Red</option>
 <option value="Green">Green</option>
 <option value="Blue">Blue</option>
 </select>
 <br><br>
 <input type=submit value="Submit">
 </form>
 </body>
 </html>

The source code for ColorPostServlet.java is shown in the following listing. The doPost( ) method is overridden to process any  HTTP POST requests that are sent to this servlet. It uses the getParameter ( ) method of HttpServletRequest to obtain the selection that was made by the user. A response is then formulated.

  import java.io.*;
  import javax.servlet.*;
  import javax.servlet.http.*;

  public class ColorPostServlet extends HttpServlet {

    public void doPost(HttpServletRequest request,
      HttpServletResponse response)
    throws ServletException, IOException {

      String color = request.getParameter("color");
      response.setContentType("text/html");
      PrintWriter pw = response.getWriter();
      pw.println("<B>The selected color is: ");
      pw.println(color);
      pw.close();
    }
  }

Compile the servlet and perform the same steps as described in the previous section to test it.

Note: Parameters for an HTTP POST request are not included as part of the URL that is sent to the Web server. In this example, the URL sent from the browser to the server is:

  http://localhost:8080/examples/servlet/ColorGetServlet

The parameter names and values are sent in the body of the HTTP request.




Using Cookies

Now, let’s develop a servlet that illustrates how to use cookies. The servlet is invoked when a form on a Web page is submitted. The example contains three files as summarized here:

File  --  Description

AddCookie.htm:  Allows a user to specify a value for the cookie named MyCookie.

AddCookieServlet.java:  Processes the submission of AddCookie.htm.

GetCookiesServlet.java:  Displays cookie values.

The HTML source code for AddCookie.htm is shown in the following listing. This page contains a text field in which a value can be entered. There is also a submit button on the page. When this button is pressed, the value in the text field is sent to AddCookieServlet via an HTTP POST request.

 <html>
 <body>
 <center>
 <form name="Form1"
   method="post"
   action="http://localhost:8080/examples/servlet/AddCookieServlet">
 <B>Enter a value for MyCookie:</B>
 <input type=textbox name="data" size=25 value="">
 <input type=submit value="Submit">
 </form>
 </body>
 </html>

The source code for AddCookieServlet.java is shown in the following listing. It gets the value of the parameter named “data”. It then creates a Cookie object that has the name “MyCookie” and contains the value of the “data” parameter. The cookie is then added to the header of the HTTP response via the addCookie( ) method. A feedback message is then written to the browser.

  import java.io.*;
  import javax.servlet.*;
  import javax.servlet.http.*;

  public class AddCookieServlet extends HttpServlet {

    public void doPost(HttpServletRequest request,
      HttpServletResponse response)
    throws ServletException, IOException {

      // Get parameter from HTTP request.
      String data = request.getParameter("data");

      // Create cookie.
      Cookie cookie = new Cookie("MyCookie", data);

      // Add cookie to HTTP response.
      response.addCookie(cookie);

      // Write output to browser.
      response.setContentType("text/html");
      PrintWriter pw = response.getWriter();
      pw.println("<B>MyCookie has been set to");
      pw.println(data);
      pw.close();
    }
  }

The source code for GetCookiesServlet.java is shown in the following listing. It invokes the getCookies( ) method to read any cookies that are included in the HTTP GET request. The names and values of these cookies are then written to the HTTP response. Observe that the getName( ) and getValue( ) methods are called to obtain this information.

  import java.io.*;
  import javax.servlet.*;
  import javax.servlet.http.*;

  public class GetCookiesServlet extends HttpServlet {

    public void doGet(HttpServletRequest request,
      HttpServletResponse response)
    throws ServletException, IOException {

      // Get cookies from header of HTTP request.
      Cookie[] cookies = request.getCookies();

      // Display these cookies.
      response.setContentType("text/html");
      PrintWriter pw = response.getWriter();
      pw.println("<B>");
      for(int i = 0; i < cookies.length; i++) {
        String name = cookies[i].getName();
        String value = cookies[i].getValue();
        pw.println("name = " + name +
          "; value = " + value);
      }
      pw.close();
    }
  }

Compile the servlet and perform these steps:
  1. Start Tomcat, if it is not already running.
  2. Display AddCookie.htm in a browser.
  3. Enter a value for MyCookie.
  4. Submit the Web page.

After completing these steps you will observe that a feedback message is displayed by the browser.

Next, request the following URL via the browser:

  http://localhost:8080/examples/servlet/GetCookiesServlet

Observe that the name and value of the cookie are displayed in the browser. In this example, an expiration date is not explicitly assigned to the cookie via the setMaxAge( ) method of Cookie. Therefore, the cookie expires when the browser session ends. You can experiment by using setMaxAge( ) and observe that the cookie is then saved to the disk on the client machine.




Session Tracking

HTTP is a stateless protocol. Each request is independent of the previous one. However, in some applications, it is necessary to save state information so that information can be collected from several interactions between a browser and a server. Sessions provide such a mechanism.

A session can be created via the getSession( ) method of HttpServletRequest. An HttpSession object is returned. This object can store a set of bindings that associate names with objects. The setAttribute( ), getAttribute( ), getAttributeNames( ), and removeAttribute( ) methods of HttpSession manage these bindings. It is important to note that session state is shared among all the servlets that are associated with a particular client.

The following servlet illustrates how to use session state. The getSession( ) method gets the current session. A new session is created if one does not already exist. The getAttribute( ) method is called to obtain the object that is bound to the name “date”. That object is a Date object that encapsulates the date and time when this page was last accessed. (Of course, there is no such binding when the page is first accessed.) A Date object encapsulating the current date and time is then created. The setAttribute( ) method is called to bind the name “date” to this object.

  import java.io.*;
  import java.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;

  public class DateServlet extends HttpServlet {

    public void doGet(HttpServletRequest request,
      HttpServletResponse response)
    throws ServletException, IOException {

      // Get the HttpSession object.
      HttpSession hs = request.getSession(true);

      // Get writer.
      response.setContentType("text/html");
      PrintWriter pw = response.getWriter();
      pw.print("<B>");

      // Display date/time of last access.
      Date date = (Date)hs.getAttribute("date");
      if(date != null) {
        pw.print("Last access: " + date + "<br>");
      }

      // Display current date/time.
      date = new Date();
      hs.setAttribute("date", date);
      pw.println("Current date: " + date);
    }
  }

When you first request this servlet, the browser displays one line with the current date and time information. On subsequent invocations, two lines are displayed. The first line shows the date and time when the servlet was last accessed. The second line shows the current date and time.


Security Issues

In earlier chapters of this book, you learned that untrusted applets are constrained to operate in a “sandbox”. They cannot perform operations that are potentially dangerous to a user’s machine. This includes reading and writing files, opening sockets to arbitrary machines, calling native methods, and creating new processes. Other restrictions also apply.

Similar constraints also exist for untrusted servlets. Code that is loaded from a remote machine is untrusted. However, trusted servlets are not limited in this manner. Trusted servlets are those which are loaded from the local machine.