java set 1

53
Java Programming Assignment Set – 1 Book ID: B0831 1. What are the difference between an interface and an abstract class? The abstract class An abstract class defines common properties and behaviors of other classes. An abstract class is used as a base class to derive specific classes of the same kind. It defines properties common to the classes derived from it. The abstract keyword is used to declare such a class. The classes declared using the abstract keyword cannot be instantiated. Syntax abstract class <class_name> { } You can also declare abstract methods. Abstract methods have public scope. The code below declares an abstract method for the class shape. abstract class shape { public abstract float calculateArea (); } The abstract method calculateArea (), given above, is inherited by the subclasses of the shape class. The subclasses Rectangle, Circle and Hexagon implement this method in different ways. Public class circle extends shape { float radius;

Upload: jimmy-jack

Post on 29-Oct-2014

127 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Java Set 1

Java Programming

Assignment Set – 1Book ID: B0831

1. What are the difference between an interface and an abstract class?

The abstract class

An abstract class defines common properties and behaviors of other classes. An abstract class is used as a base class to derive specific classes of the same kind. It defines properties common to the classes derived from it. The abstract keyword is used to declare such a class. The classes declared using the abstract keyword cannot be instantiated.

Syntax

abstract class <class_name>

{

}

You can also declare abstract methods. Abstract methods have public scope. The code below declares an abstract method for the class shape.

abstract class shape

{

public abstract float calculateArea ();

}

The abstract method calculateArea (), given above, is inherited by the subclasses of the shape class. The subclasses Rectangle, Circle and Hexagon implement this method in different ways.

Public class circle extends shape

{

float radius;

public float calculateArea ()

{

return radius*22/7;

}

}

In the above example, the calculateArea () method has been overridden in the circle class. If the method is not overridden, the class will inherit the abstract method from the parent class. Any class that has a abstract method is abstract. Hence, you would not be able to create an object of

Page 2: Java Set 1

the circle class. Therefore, it is necessary to override the calculateArea () method in the circle class.

Interface

Using the keyword interface, you can fully abstract a class' interface from its implementation. That is, using interface, you can specify what a class must do, but not how it does it. Interfaces are syntactically similar to classes, but they lack instance variables, and their methods are declared without any body. In practice, this means that you can define interfaces which don't make assumptions about how they are implemented. Once it is defined, any number of classes can implement an interface.

Also, one class can implement any number of interfaces. To implement an interface, a class must create the complete set of methods defined by the interface. However, each class is free to determine the details of its own implementation. By providing the interface keyword, Java allows you to fully utilize the "one interface, multiple methods" aspect of polymorphism.

Interfaces are designed to support dynamic method resolution at run time. Normally, in order for a method to be called from one class to another, both classes need to be present at compile time so the Java compiler can check to ensure that the method signatures are compatible. This requirement by itself makes for a static and nonextensible classing environment. Inevitably in a system like this, functionality gets pushed up higher and higher in the class hierarchy so that the mechanisms will be available to more and more subclasses. Interfaces are designed to avoid this problem.They disconnect the definition of a method or set of methods from the inheritance hierarchy. Since interfaces are in a different hierarchy from classes, it is possible for classes that are unrelated in terms of the class hierarchy to implement the same interface. This is where the real power of interfaces is realized.

Interfaces add most of the functionality that is required for many applications

which would normally resort to using multiple inheritance in a language such? as C++.

Defining an Interface

An interface is defined much like a class. This is the general form of an interface:

access interface name {

return-type method-name1 (parameter-list);

return-type method-name2(parameter-list);

type final-varname1 = value;

type final-varname2 = value;

// ...

return-type method-nameN (parameter-list);

type final-varnameN = value;

}

Page 3: Java Set 1

Here, access is either public or not used. When no access specifier is included, then default access results, and the interface is only available to other members of the package in which it is declared. When it is declared as public, the interface can be used by any other code. name is the name of the interface, and can be any valid identifier. Notice that the methods which are declared have no bodies. They end with a semicolon after the parameter list. They are, essentially, abstract methods; there can be no default implementation of any method specified within an interface. Each class that includes an interface must implement all of the methods.

Variables can be declared inside of interface declarations. They are implicitly final and static, meaning they cannot be changed by the implementing class. They must also be initialized with a constant value. All methods and variables are implicitly public if the interface, itself, is declared as public.

Here is an example of an interface definition. It declares a simple interface which contains one method called callback ( ) that takes a single integer parameter.

interface Callback {

void callback (int param);

}

Some uses of interfaces

· Interfaces are a way of saying, “You need to plug some code in here for this thing to fully work “. The interfaces specify the exact signatures of the methods that must be provided.

· Use the interface type as a parameter for a method. Inside the method you can invoke any of the methods promised by the interface parameter. When you actually call the method, you will have to provide an object that has all the methods promised by the interface. It might help to think of this as a bit like passing in a subclass as an argument and having the correct overriding methods called.

· Interfaces can be used to mix in generally useful constants. So, for example, if an interface defines a set of constants, and then multiple classes use those constants, the values of those constants could be globally changed without having to modify multiple classes. That is interfaces separate design from implementation.

Interfaces verses abstract classes

While an interface is used to specify the form that something must have, it does not actually provide the implementation for it. In this sense, an interface is a little like an abstract class that must be extended in exactly the manner that its abstract methods specify.

· An abstract class is an incomplete class that requires further specialization. An interface is just a specification or prescription for behavior.

· An interface does not have any overtones of specialization that are present with inheritance.

· A class can implement several interfaces at once, whereas a class can extend only one parent class.

Page 4: Java Set 1

· Interfaces can be used to support callbacks (inheritance does not help with this). This is a significant coding idiom. It essentially provides a pointer to a function, but in a type-safe way. Callback is explained in the next section.

2. Explain the following with respect to Inheritance in Java: a. Various Access Specifiers and their usage b. Abstract classes and their applications

Inheritance

Inheritance is one of the cornerstones of object-oriented programming because it allows the creation of hierarchical classifications. Using inheritance, you can create a general class that defines traits common to a set of related items. This class can then be inherited by other, more specific classes, each adding those things that are unique to it. In the terminology of Java, a class that is inherited is called a superclass. The class that does the

inheriting is called a subclass. Therefore, a subclass is a specialized version of a superclass. It inherits all of the instance variables and methods defined by the superclass and add its own, unique elements.

Types of Relationships

Relationships are classified as follows:

· A Kind-Of relationship.

· A Is-A relationship.

· A Part-Of-relationship.

· A Has-A relationship.

Consider for a moment the similarities and differences among the following objects/classes: Automobile, Ford, Porsche, Car and Engine. We can make the following observations:

· A truck is a kind of an automobile.

· A car is a (different) kind of an automobile.

· An engine is a part of an automobile.

· An automobile has an engine.

· The ford is a car.

A-Kind-Of Relationship

Taking the example of a human being and a elephant, both are ‘kind-of’ mammals. As human beings and elephants are ‘kind-of’ mammals, they share the attributes and behaviors of mammals. Human being and elephants are subset of the mammals class. The following figure depicts the relationship between the Mammals and Human Begin classes:

Page 5: Java Set 1

Is-A Relationship

Let’s take an instance of the human being class – peter, who ‘is –a’ human being and, therefore, a mammal. The following figure depicts the ‘is –a’ relationship.

Has-A Relationship/Part-Of Relationship

A human being has a heart. This represents a has-a relationship. The following figure depicts the relationship between a human being and a heart.

What is Inheritance?

The philosophy behind inheritance is to portray things as they exist in the real world. For instance, a child inherits properties from both the parents. Inheritance means that a class derives a set of attributes and related behaviors from another class.

Inheritance helps you to:

· Reduce redundancy in code. Code redundancy means writing the same code in different places, leading to unnecessary replication of code. Inheritance helps you to reuse code.

· Maintain code easily, as the code resides at one place (superclass). Any changes made to the superclass automatically change the behavior automatically.

· Extend the functionality of an existing class by adding more methods to the subclass.

Implementing Inheritance in Java

The extends keyword is used to derive a class from a superclass, or in other words, extend the functionality of a superclass.

Syntax

Page 6: Java Set 1

public class <subclass_name>extends<superclass_name>

Example

public class confirmed extends ticket

{

}

Access Specifiers

An access specifier determines which features of a class (the class itself, the data members, and the methods) may be used by other classes. Java supports three access specifiers.

· public.

· private.

· protected.

The public Access Specifiers

All classes except inner class (class within classes) can have the public access specifier. You can use a public class, a data member, or a method from any object in any Java program.

Example

public class publicclass

{

public int publicvaraible;

public void publicmethod ()

{

}

}

The private Access Specifier

Only objects of the same class can access a private variable or method. You can declare only variables, methods, and inner classes as private.

Example

private int privatevariable;

The protected Access Specifier

The variables, methods, and inner classes that are declared protected are accessible to the subclasses of the class in which they are declared.

Example

protected int protectedvariable;

Page 7: Java Set 1

Default Access

If you do not specify any of the above access specifiers, the scope is friendly. A class, variable, or method that has friendly access is accessible to all the classes of a package.

Consider the following set of classes. Class Y and Z inherit from class X. Class Z belongs to a package different than that of classes X and Y

A method accessMe () has been declared in class X. The following table shows you the accessibility of the method accessMe () from classes Y and Z

You can access a non-private variable or method using an object of the class as shown below:

Someclass classobject = new someclass ();

Classobject.publicvariable;

Classobject.protectedmethod ();

Although a subclass includes all of the members of its superclass, it cannot access those members of the superclass that have been declared as private. For example, consider the following simple class hierarchy:

/* In a class hierarchy, private members remain

private to their class.

This program contains an error and will not

Page 8: Java Set 1

compile.

*/

// Create a superclass.

class A {

int i; // public by default

private int j; // private to A

void setij(int x, int y) {

i = x;

j = y;

}

}

// A's j is not accessible here.

class B extends A {

int total;

void sum() {

total = i + j; // ERROR, j is not accessible here

}

}

class Access {

public static void main(String args[]) {

B subOb = new B();

subOb.setij(10, 12);

subOb.sum();

System.out.println("Total is " + subOb.total);

}

}

This program will not compile because the reference to j inside the sum( ) method of B causes an access violation. Since j is declared as private, it is only accessible by other members of its own class. Subclasses have no access to it.

Note: A class member that has been declared as private will remain private to its class. It is not accessibl e by any code outside its class, including subclasses.

Page 9: Java Set 1

A Superclass Variable Can Reference a Subclass Object

A reference variable of a superclass can be assigned a reference to any subclass derived from that superclass. You will find this aspect of inheritance quite useful in a variety of situations. For example, consider the following:

class RefDemo {

public static void main(String args[]) {

BoxWeight weightbox = new BoxWeight(3, 5, 7, 8.37);

Box plainbox = new Box();

double vol;

vol = weightbox.volume();

System.out.println("Volume of weightbox is " + vol);

System.out.println("Weight of weightbox is " +

weightbox.weight);

System.out.println();

// assign BoxWeight reference to Box reference

plainbox = weightbox;

vol = plainbox.volume(); // OK, volume() defined in Box

System.out.println("Volume of plainbox is " + vol);

/* The following statement is invalid because plainbox

does not define a weight member. */

// System.out.println("Weight of plainbox is " +

plainbox.weight);

}

}

Here, weightbox is a reference to BoxWeight objects, and plainbox is a reference to Box objects. Since BoxWeight is a subclass of Box, it is permissible to assign plainbox a reference to the weightbox object.

It is important to understand that it is the type of the reference variable—not the type of the object that it refers to—that determines what members can be accessed. That is, when a reference to a subclass object is assigned to a superclass reference variable, you will have access only to those parts of the object defined by the superclass. This is why plainbox can't access weight even when it refers to a BoxWeight object. If you think about it, this makes sense, because the superclass has no knowledge of what a subclass adds to it. This is why the last line of code in the

Page 10: Java Set 1

preceding fragment is commented out. It is not possible for a Box reference to access the weight field, because it does not define one.

Although the preceding may seem a bit esoteric, it has some important practical applications – two of which are discussed later in this chapter.

Using super

In the preceding examples, classes derived from Box were not implemented as efficiently or as robustly as they could have been. For example, the constructor for BoxWeight explicitly initializes the width, height, and depth fields of Box( ). Not only does this duplicate code found in its superclass, which is inefficient, but it implies that a subclass must be granted access to these members. However, there will be times when you will want to create a superclass that keeps the details of its implementation to itself (that is, that keeps its data members private). In this case, there would be no way for a subclass to directly access or initialize these variables on its own. Since encapsulation is a primary attribute of OOP, it is not surprising that Java provides a solution to this problem. Whenever a subclass needs to refer to its immediate superclass, it can do so by use of the keyword super.

super has two general forms. The first calls the superclass' constructor. The second is used to access a member of the superclass that has been hidden by a member of a subclass. Each use is examined here.

Using super to Call Superclass Constructors

A subclass can call a constructor method defined by its superclass by use of the following form of super:

super(parameter-list);

Here, parameter-list specifies any parameters needed by the constructor in the superclass. super( ) must always be the first statement executed inside a subclass' constructor. To see how super( ) is used, consider this improved version of the BoxWeight( ) class:

// BoxWeight now uses super to initialize its Box attributes.

class BoxWeight extends Box {

double weight; // weight of box

// initialize width, height, and depth using super()

BoxWeight(double w, double h, double d, double m) {

super(w, h, d); // call superclass constructor

weight = m;

}

}

Here, BoxWeight( ) calls super( ) with the parameters w, h, and d. This causes the Box( ) constructor to be called, which initializes width, height, and depth using these values.

Page 11: Java Set 1

BoxWeight no longer initializes these values itself. It only needs to initialize the value unique to it: weight. This leaves Box free to make these values private if desired.

In the preceding example, super( ) was called with three arguments. Since constructors can be overloaded, super( ) can be called using any form defined by the superclass. The constructor executed will be the one that matches the arguments. For example, here is a complete implementation of BoxWeight that provides constructors for the various ways that a box can be constructed. In each case, super( ) is called using the appropriate arguments. Notice that width, height, and depth have been made private within Box.

// A complete implementation of BoxWeight.

class Box {

private double width;

private double height;

private double depth;

// construct clone of an object

Box(Box ob) { // pass object to constructor

width = ob.width;

height = ob.height;

depth = ob.depth;

}

// constructor used when all dimensions specified

Box(double w, double h, double d) {

width = w;

height = h;

depth = d;

}

// constructor used when no dimensions specified

Box() {

width = -1; // use -1 to indicate

height = -1; // an uninitialized

depth = -1; // box

}

// constructor used when cube is created

Page 12: Java Set 1

Box(double len) {

width = height = depth = len;

}

// compute and return volume

double volume() {

return width * height * depth;

}

}

// BoxWeight now fully implements all constructors.

class BoxWeight extends Box {

double weight; // weight of box

// construct clone of an object

BoxWeight(BoxWeight ob) { // pass object to constructor

super(ob);

weight = ob.weight;

}

// constructor when all parameters are specified

BoxWeight(double w, double h, double d, double m) {

super(w, h, d); // call superclass constructor

weight = m;

}

// default constructor

BoxWeight() {

super();

weight = -1;

}

// constructor used when cube is created

BoxWeight(double len, double m) {

super(len);

weight = m;

Page 13: Java Set 1

}

}

class DemoSuper {

public static void main(String args[]) {

BoxWeight mybox1 = new BoxWeight(10, 20, 15, 34.3);

BoxWeight mybox2 = new BoxWeight(2, 3, 4, 0.076);

BoxWeight mybox3 = new BoxWeight(); // default

BoxWeight mycube = new BoxWeight(3, 2);

BoxWeight myclone = new BoxWeight(mybox1);

double vol;

vol = mybox1.volume();

System.out.println("Volume of mybox1 is " + vol);

System.out.println("Weight of mybox1 is " + mybox1.weight);

System.out.println();

vol = mybox2.volume();

System.out.println("Volume of mybox2 is " + vol);

System.out.println("Weight of mybox2 is " + mybox2.weight);

System.out.println();

vol = mybox3.volume();

System.out.println("Volume of mybox3 is " + vol);

System.out.println("Weight of mybox3 is " + mybox3.weight);

System.out.println();

vol = myclone.volume();

System.out.println("Volume of myclone is " + vol);

System.out.println("Weight of myclone is " + myclone.weight);

System.out.println();

vol = mycube.volume();

System.out.println("Volume of mycube is " + vol);

System.out.println("Weight of mycube is " + mycube.weight);

System.out.println();

Page 14: Java Set 1

}

}

This program generates the following output:

Volume of mybox1 is 3000.0

Weight of mybox1 is 34.3

Volume of mybox2 is 24.0

Weight of mybox2 is 0.076

Volume of mybox3 is -1.0

Weight of mybox3 is -1.0

Volume of myclone is 3000.0

Weight of myclone is 34.3

Volume of mycube is 27.0

Weight of mycube is 2.0

Pay special attention to this constructor in BoxWeight( ):

// construct clone of an object

BoxWeight(BoxWeight ob) { // pass object to constructor

super(ob);

weight = ob.weight;

}

Notice that super( ) is called with an object of type BoxWeight—not of type Box. This still invokes the constructor Box(Box ob). As mentioned earlier, a superclass variable can be used to reference any object derived from that class. Thus, we are able to pass a BoxWeight object to the Box constructor. Of course, Box only has knowledge of its own members.

Let's review the key concepts behind super( ). When a subclass calls super( ), it is calling the constructor of its immediate superclass. Thus, super( ) always refers to the superclass immediately above the calling class. This is true even in a multileveled hierarchy. Also, super( ) must always be the first statement executed inside a subclass constructor.

A Second Use for super

The second form of super acts somewhat like this, except that it always refers to the superclass of the subclass in which it is used. This usage has the following general form:

super.member

Here, member can be either a method or an instance variable.

Page 15: Java Set 1

This second form of super is most applicable to situations in which member names of a subclass hide members by the same name in the superclass. Consider this simple class hierarchy:

// Using super to overcome name hiding.

class A {

int i;

}

// Create a subclass by extending class A.

class B extends A {

int i; // this i hides the i in A

B(int a, int b) {

super.i = a; // i in A

i = b; // i in B

}

void show() {

System.out.println("i in superclass: " + super.i);

System.out.println("i in subclass: " + i);

}

}

class UseSuper {

public static void main(String args[]) {

B subOb = new B(1, 2);

subOb.show();

}

}

This program displays the following:

i in superclass: 1

i in subclass: 2

Although the instance variable i in B hides the i in A, super allows access to the i defined in the superclass. As you will see, super can also be used to call methods that are hidden by a subclass.

The abstract class

Page 16: Java Set 1

An abstract class defines common properties and behaviors of other classes. An abstract class is used as a base class to derive specific classes of the same kind. It defines properties common to the classes derived from it. The abstract keyword is used to declare such a class. The classes declared using the abstract keyword cannot be instantiated.

Syntax

abstract class <class_name>

{

}

You can also declare abstract methods. Abstract methods have public scope. The code below declares an abstract method for the class shape.

abstract class shape

{

public abstract float calculateArea ();

}

The abstract method calculateArea (), given above, is inherited by the subclasses of the shape class. The subclasses Rectangle, Circle and Hexagon implement this method in different ways.

Public class circle extends shape

{

float radius;

public float calculateArea ()

{

return radius*22/7;

}

}

In the above example, the calculateArea () method has been overridden in the circle class. If the method is not overridden, the class will inherit the abstract method from the parent class. Any class that has a abstract method is abstract. Hence, you would not be able to create an object of the circle class. Therefore, it is necessary to override the calculateArea () method in the circle class.

The final Keyword

A class called password authenticates user login. You do not want anybody to change the functionality of the class by extending it. To prevent inheritance, use the final modifier.

Example

final class password

Page 17: Java Set 1

{

}

You will also find final classes in JDK package. For example, the java.lang.String class has been declared final. This is done for security reasons. It ensure that any method that refers to the String class gets the actual String class and not a modified one.

3. Describe Exception Handling in JAVA

The term exception denotes an exceptional event. It can be defined as an abnormal event that occurs during program execution and disrupts the normal flow of instruction.

Error-handling becomes a necessity when you develop applications that need to take care of unexpected situations. The unexpected situations that may occur during program execution are:

· Running out of memory

· Resource allocation errors.

· Inability to find a file.

· Problems in network connectivity.

If an above-mentioned situation is encountered, a program may stop working. You cannot afford to have an application stop working or crashing, if the requested file is not present on the disk. Traditionally, programmers used return values of methods to detect the errors that occurred at runtime. A variable errno was used for a numeric representation of the error. When multiple errors occurred in a method, errno would have only one value-that of the last error that occurred in the method.

Java handles exceptions the object-oriented way. You can use a hierarchy of exception classes to manage runtime errors.

Exception Classes

The class at the top of the exception classes hierarchy is called Throwable. Two classes are derived from the Throwable class- Error and Exception. The Exception class is used fro the exceptional conditions that have to be trapped in a program. The Error class defines a condition that does not occur under normal circumstances. In other words, the Error class is used for catastrophic failures such as VirtualMachineError. These classes are available in the java.lang package.

Common Exceptions

Java has several predefined exceptions. The most common exceptions that you may encounter are described below.

· Arithmetic Exception

This exception is thrown when an exceptional arithmetic condition has occurred. For example, a division by zero generates such an exception.

Page 18: Java Set 1

· NullPointer Exception

This exception is thrown when an application attempts to use null where an object is required. An object that has not been allocated memory holds a null value. The situations in which an exception is thrown include:

- Using an object without allocating memory for it.

- Calling the methods of a null object.

- Accessing or modifying the attributes of a null object.

· ArrayIndexOutOfBounds Exception

The exception ArrayIndexOutOfBounds Exception is thrown when an attempt is made to access an array element beyond the index of the array. For example, if you try to access the eleventh element of an array that’s has only ten elements, the exception will be thrown.

Exception Handling Techniques

When an unexpected error occurs in a method, Java creates an object of the appropriate exception class. After creating the exception objects, Java passes it to the program, by an action called throwing an exception. The exception object contains information about the type of error and the state of the program when the exception occurred. You need to handle the exception using exception-handler and process the exception.

You can implement exception-handling in your program by using following keywords:

· try

· catch

· finally

The try Block

You need to guard the statements that may throw an exception in the try block. The following skeletal code illustrates the use of the try block

try

{

// statement that may cause an exception

}

The try block governs the statements that are enclosed within it and defines the scope of the exception handlers associated with it. In other words, if an exception occurs within try block, the appropriate exception-handler that is associated with the try block handles the exception. A try block must have at least one catch block that follow it immediately.

Nested try Statements

The try statement can be nested. That is, a try statement can be inside the block of another try. Each time a try statement is entered, the context of that exception is pushed on the stack. If an

Page 19: Java Set 1

inner try statement does not have a catch handler for a particular exception, the stack is unwound and the next try statement's catch handlers are inspected for a match. This continues until one of the catch statements succeeds, or until all of the nested try statements are exhausted. If no catch statement matches, then the Java run-time system will handle the exception. Here is an example that uses nested try

statements:

// An example of nested try statements.

class NestTry {

public static void main(String args[ ]) {

try {

int a = args.length;

/* If no command-line args are present,

the following statement will generate

a divide-by-zero exception. */

int b = 42 / a;

System.out.println("a = " + a);

try { // nested try block

/* If one command-line arg is used,

then a divide-by-zero exception

will be generated by the following code. */

if(a==1) a = a/(a-a); // division by zero

/* If two command-line args are used,

then generate an out-of-bounds exception. */

if(a==2) {

int c[ ] = { 1 };

c[42] = 99; // generate an out-of-bounds exception

}

} catch(ArrayIndexOutOfBoundsException e) {

}

} catch(ArithmeticException e) {

System.out.println("Divide by 0: " + e);

}

Page 20: Java Set 1

}

}

As you can see, this program nests one try block within another. The program works as follows. When you execute the program with no command-line arguments, a divide-by zero exception is generated by the outer try block. Execution of the program by one command-line argument generates a divide-by-zero exception from within the nested try block. Since the inner block does not catch this exception, it is passed on to the outer try block, where it is handled. If you execute the program with two command-line arguments, an array boundary exception is generated from within the inner try block. Here are sample runs that illustrate each case:

C:\>java NestTry

Divide by 0: java.lang.ArithmeticException: / by zero

C:\>java NestTry One

a = 1

Divide by 0: java.lang.ArithmeticException: / by zero

C:\>java NestTry One Two

a = 2

Array index out-of-bounds:

java.lang.ArrayIndexOutOfBoundsException: 42

Nesting of try statements can occur in less obvious ways when method calls are involved. For example, you can enclose a call to a method within a try block. Inside that method is another try statement. In this case, the try within the method is still nested inside the outer try block, which calls the method. Here is the previous program recoded so that the nested try block is moved inside the method nesttry( ):

/* Try statements can be implicitly nested via

calls to methods. */

class MethNestTry {

static void nesttry(int a) {

try { // nested try block

/* If one command-line arg is used,

then a divide-by-zero exception

will be generated by the following code. */

if(a==1) a = a/(a-a); // division by zero

/* If two command-line args are used,

then generate an out-of-bounds exception. */

Page 21: Java Set 1

if(a==2) {

int c[ ] = { 1 };

c[42] = 99; // generate an out-of-bounds exception

}

} catch(ArrayIndexOutOfBoundsException e) {

System.out.println("Array index out-of-bounds: " + e);

}

}

public static void main(String args[ ]) {

try {

int a = args.length;

/* If no command-line args are present,

the following statement will generate

a divide-by-zero exception. */

int b = 42 / a;

System.out.println("a = " + a);

nesttry(a);

} catch(ArithmeticException e) {

System.out.println("Divide by 0: " + e);

}

}

}

The output of this program is identical to that of the preceding example.

The catch Block

You associate an exception-handler with the try block by providing one or more catch handlers immediately after try block. The following skeletal code illustrates the use of the catch block.

try

{

//statements that may cause an exception

}

catch ()

Page 22: Java Set 1

{

// error handling code

}

The catch statement takes an object of an exception class as a parameter. If an exception is thrown, the statements in the catch block are executed. The scope of the catch block is restricted to the statements in the preceding try block only.

The finally Block

When an exception is raised, the rest of the statements in the try block are ignored. Sometimes, it is necessary to process certain statements irrespective of whether an exception is raised or not. The finally block is used for this purpose.

try

{

openFile();

writeFile(); //may cause an exception

}

catch (…)

{

//process the exception

}

In the above example, the file has to be closed irrespective of whether an exception is raised or not. You can place the code to close the file in both the try and catch blocks. To avoid duplication of code, you can place the code in the finally block. The code in the finally block is executed regardless of whether an exception is thrown or not. The finally block follows the catch blocks. You have only one finally block for an exception-handler. However, it is not mandatory to have a finally block.

finally

{

closeFile ();

}

Page 23: Java Set 1

Book ID: B0832

4. What do you mean by Object Adapter? Explain with an example?

Object Adapters

The CORBA specification defines the concept of an object adapter. An object adapter is a framework for implementing CORBA objects. It provides an API that object implementations use for various low level services. According to the CORBA specification, an object adapter is responsible for the following functions:

· Generation and interpretation of object references

· Method invocation

· Security of interactions

· Object and implementation activation and deactivation

· Mapping object references to the corresponding object implementations

· Registration of implementations

The architecture supports the definition of many kinds of object adapters. The specification includes the definition of the basic object adapter (BOA). In the previous section, you saw some server code that uses the services of VisiBroker's implementation of the BOA. The BOA has been implemented in various CORBA products. Unfortunately, since the specification of the BOA was not complete, the various BOA implementations differ in some significant ways. This has compromised server portability.

To address this shortcoming, an entirely new object adapter was added, the portable object adapter (POA). Unfortunately, the POA is not yet supported in many products. In any event, the BOA and the POA are described here.

Activation on Demand by the Basic Object Adapter (BOA)

One of the main tasks of the BOA is to support on-demand object activation. When a client issues a request, the BOA determines if the object is currently running and if so, it delivers the request to the object. If the object is not running, the BOA activates the object and then delivers the request.

The BOA defines four different models for object activation:

Shared server Multiple active objects share the same server. The server services requests from multiple clients. The server remains active until it is deactivated or exits.

Unshared server Only one object is active in the server. The server exits when the client that caused its activation exits.

Page 24: Java Set 1

Server-per-method Each request results in the creation of a server. The server exits when the method completes.

Persistent server The server is started by an entity other than the BOA (you, operating services, etc.). Multiple active objects share the server.

5. Describe the following with respect to implementation of Sockets in Java: a. Reading from and Writing to a Socket b. Writing the Server Side of a Socket

Normally, a server runs on a specific computer and has a socket that is bound to a specific port number. The server just waits, listening to the socket for a client to make a connection request.

On the client-side: The client knows the hostname of the machine on which the server is running and the port number on which the server is listening. To make a connection request, the client tries to rendezvous with the server on the server's machine and port. The client also needs to identify itself to the server so it binds to a local port number that it will use during this connection. This is usually assigned by the system.

If everything goes well, the server accepts the connection. Upon acceptance, the server gets a new socket bound to the same local port and also has its remote endpoint set to the address and port of the client. It needs a new socket so that it can continue to listen to the original socket for connection requests while tending to the needs of the connected client.

On the client side, if the connection is accepted, a socket is successfully created and the client can use the socket to communicate with the server.

The client and server can now communicate by writing to or reading from their sockets.

Definition: A socket is one endpoint of a two-way communication link between two programs running on the network. A socket is bound to a port number so that the TCP layer can identify the application that data is destined to be sent.

Page 25: Java Set 1

An endpoint is a combination of an IP address and a port number. Every TCP connection can be uniquely identified by its two endpoints. That way you can have multiple connections between your host and the server.

The java.net package in the Java platform provides a class, Socket, that implements one side of a two-way connection between your Java program and another program on the network. The Socket class sits on top of a platform-dependent implementation, hiding the details of any particular system from your Java program. By using the java.net.Socket class instead of relying on native code, your Java programs can communicate over the network in a platform-independent fashion.

Additionally, java.net includes the ServerSocket class, which implements a socket that servers can use to listen for and accept connections to clients. This lesson shows you how to use the Socket and ServerSocket classes.

If you are trying to connect to the Web, the URL class and related classes (URLConnection, URLEncoder) are probably more appropriate than the socket classes. In fact, URLs are a relatively high-level connection to the Web and use sockets as part of the underlying implementation. See Working with URLs for information about connecting to the Web via URLs.

Reading from and Writing to a Socket

Let's look at a simple example that illustrates how a program can establish a connection to a server program using the Socket class and then, how the client can send data to and receive data from the server through the socket.

The example program implements a client, EchoClient, that connects to the Echo server. The Echo server simply receives data from its client and echoes it back. The Echo server is a well-known service that clients can rendezvous with on port 7.

EchoClient creates a socket thereby getting a connection to the Echo server. It reads input from the user on the standard input stream, and then forwards that text to the Echo server by writing the text to the socket. The server echoes the input back through the socket to the client. The client program reads and displays the data passed back to it from the server:

import java.io.*;

import java.net.*;

public class EchoClient {

public static void main(String[] args) throws IOException {

Socket echoSocket = null;

PrintWriter out = null;

BufferedReader in = null;

try {

Page 26: Java Set 1

echoSocket = new Socket("taranis", 7);

out = new PrintWriter(echoSocket.getOutputStream(), true);

in = new BufferedReader(new InputStreamReader(

echoSocket.getInputStream()));

} catch (UnknownHostException e) {

System.err.println("Don't know about host: taranis.");

System.exit(1);

} catch (IOException e) {

System.err.println("Couldn't get I/O for "

+ "the connection to: taranis.");

System.exit(1);

}

BufferedReader stdIn = new BufferedReader(

new InputStreamReader(System.in));

String userInput;

while ((userInput = stdIn.readLine()) != null) {

out.println(userInput);

System.out.println("echo: " + in.readLine());

}

out.close();

in.close();

stdIn.close();

echoSocket.close();

}

Page 27: Java Set 1

}

Note that EchoClient both writes to and reads from its socket, thereby sending data to and receiving data from the Echo server.

Let's walk through the program and investigate the interesting parts. The three statements in the try block of the main method are critical. These lines establish the socket connection between the client and the server and open a PrintWriter and a BufferedReader on the socket:

echoSocket = new Socket("taranis", 7);

out = new PrintWriter(echoSocket.getOutputStream(), true);

in = new BufferedReader(new InputStreamReader(

echoSocket.getInputStream()));

The first statement in this sequence creates a new Socket object and names it echoSocket. The Socket constructor used here requires the name of the machine and the port number to which you want to connect. The example program uses the host name taranis. This is the name of a hypothetical machine on our local network. When you type in and run this program on your machine, change the host name to the name of a machine on your network. Make sure that the name you use is the fully qualified IP name of the machine to which you want to connect. The second argument is the port number. Port number 7 is the port on which the Echo server listens.

The second statement gets the socket's output stream and opens a PrintWriter on it. Similarly, the third statement gets the socket's input stream and opens a BufferedReader on it. The example uses readers and writers so that it can write Unicode characters over the socket.

To send data through the socket to the server, EchoClient simply needs to write to the PrintWriter. To get the server's response, EchoClient reads from the BufferedReader. The rest of the program achieves this. If you are not yet familiar with the Java platform's I/O classes, you may wish to read Basic I/O.

The next interesting part of the program is the while loop. The loop reads a line at a time from the standard input stream and immediately sends it to the server by writing it to the PrintWriter connected to the socket:

String userInput;

while ((userInput = stdIn.readLine()) != null) {

out.println(userInput);

System.out.println("echo: " + in.readLine());

}

Page 28: Java Set 1

The last statement in the while loop reads a line of information from the BufferedReader connected to the socket. The readLine method waits until the server echoes the information back to EchoClient. When readline returns, EchoClient prints the information to the standard output.

The while loop continues until the user types an end-of-input character. That is, EchoClient reads input from the user, sends it to the Echo server, gets a response from the server, and displays it, until it reaches the end-of-input. The while loop then terminates and the program continues, executing the next four lines of code:

out.close();

in.close();

stdIn.close();

echoSocket.close();

These lines of code fall into the category of housekeeping. A well-behaved program always cleans up after itself, and this program is well-behaved. These statements close the readers and writers connected to the socket and to the standard input stream, and close the socket connection to the server. The order here is important. You should close any streams connected to a socket before you close the socket itself.

This client program is straightforward and simple because the Echo server implements a simple protocol. The client sends text to the server, and the server echoes it back. When your client programs are talking to a more complicated server such as an HTTP server, your client program will also be more complicated. However, the basics are much the same as they are in this program:

1. Open a socket.

2. Open an input stream and output stream to the socket.

3. Read from and write to the stream according to the server's protocol.

4. Close the streams.

5. Close the socket.

Only step 3 differs from client to client, depending on the server. The other steps remain largely the same.

Writing the Server Side of a Socket

This section shows you how to write a server and the client that goes with it. The server in the client/server pair serves up Knock Knock jokes. Knock Knock jokes are favored by children and are usually vehicles for bad puns. They go like this:

Server:"Knockknock!" Client:"Who'sthere?" Server:"Dexter." Client:"Dexterwho?"

Page 29: Java Set 1

Server:"Dexterhallswithboughsofholly." Client: "Groan."

The example consists of two independently running Java programs: the client program and the server program. The client program is implemented by a single class, KnockKnockClient, and is very similar to the EchoClient example from the previous section. The server program is implemented by two classes: KnockKnockServer and KnockKnockProtocol, KnockKnockServer contains the main method for the server program and performs the work of listening to the port, establishing connections, and reading from and writing to the socket. KnockKnockProtocol serves up the jokes. It keeps track of the current joke, the current state (sent knock knock, sent clue, and so on), and returns the various text pieces of the joke depending on the current state. This object implements the protocol-the language that the client and server have agreed to use to communicate.

The following section looks in detail at each class in both the client and the server and then shows you how to run them.

The Knock Knock Server

This section walks through the code that implements the Knock Knock server program. Here is the complete source for the KnockKnockServer class.

The server program begins by creating a new ServerSocket object to listen on a specific port (see the statement in bold in the following code segment). When writing a server, choose a port that is not already dedicated to some other service. KnockKnockServer listens on port 4444 because 4 happens to be my favorite number and port 4444 is not being used for anything else in my environment:

try {

serverSocket = new ServerSocket(4444);

} catch (IOException e) {

System.out.println("Could not listen on port: 4444");

System.exit(-1);

}

ServerSocket is a java.net class that provides a system-independent implementation of the server side of a client/server socket connection. The constructor for ServerSocket throws an exception if it can't listen on the specified port (for example, the port is already being used). In this case, the KnockKnockServer has no choice but to exit.

If the server successfully binds to its port, then the ServerSocket object is successfully created and the server continues to the next step--accepting a connection from a client (shown in bold):

Socket clientSocket = null;

Page 30: Java Set 1

try {

clientSocket = serverSocket.accept();

} catch (IOException e) {

System.out.println("Accept failed: 4444");

System.exit(-1);

}

The accept method waits until a client starts up and requests a connection on the host and port of this server (in this example, the server is running on the hypothetical machine taranis on port 4444). When a connection is requested and successfully established, the accept method returns a new Socket object which is bound to the same local port and has it's remote address and remote port set to that of the client. The server can communicate with the client over this new Socket and continue to listen for client connection requests on the original ServerSocket This particular version of the program doesn't listen for more client connection requests. However, a modified version of the program is provided in Supporting Multiple Clients.

After the server successfully establishes a connection with a client, it communicates with the client using this code:

PrintWriter out = new PrintWriter(

clientSocket.getOutputStream(), true);

BufferedReader in = new BufferedReader(

new InputStreamReader(

clientSocket.getInputStream()));

String inputLine, outputLine;

// initiate conversation with client

KnockKnockProtocol kkp = new KnockKnockProtocol();

outputLine = kkp.processInput(null);

out.println(outputLine);

while ((inputLine = in.readLine()) != null) {

outputLine = kkp.processInput(inputLine);

out.println(outputLine);

Page 31: Java Set 1

if outputLine.equals("Bye."))

break;

}

This code:

1. Gets the socket's input and output stream and opens readers and writers on them.

2. Initiates communication with the client by writing to the socket (shown in bold).

3. Communicates with the client by reading from and writing to the socket (the while loop).

Step 1 is already familiar. Step 2 is shown in bold and is worth a few comments. The bold statements in the code segment above initiate the conversation with the client. The code creates a KnockKnockProtocol object-the object that keeps track of the current joke, the current state within the joke, and so on.

After the KnockKnockProtocol is created, the code calls KnockKnockProtocol's processInput method to get the first message that the server sends to the client. For this example, the first thing that the server says is "Knock! Knock!" Next, the server writes the information to the PrintWriter connected to the client socket, thereby sending the message to the client.

Step 3 is encoded in the while loop. As long as the client and server still have something to say to each other, the server reads from and writes to the socket, sending messages back and forth between the client and the server.

The server initiated the conversation with a "Knock! Knock!" so afterwards the server must wait for the client to say "Who's there?" As a result, the while loop iterates on a read from the input stream. The readLine method waits until the client responds by writing something to its output stream (the server's input stream). When the client responds, the server passes the client's response to the KnockKnockProtocol object and asks the KnockKnockProtocol object for a suitable reply. The server immediately sends the reply to the client via the output stream connected to the socket, using a call to println. If the server's response generated from the KnockKnockServer object is "Bye." this indicates that the client doesn't want any more jokes and the loop quits.

The KnockKnockServer class is a well-behaved server, so the last several lines of this section of KnockKnockServer clean up by closing all of the input and output streams, the client socket, and the server socket:

out.close();

in.close();

clientSocket.close();

serverSocket.close();

Page 32: Java Set 1

The Knock Knock Protocol

The KnockKnockProtocol class implements the protocol that the client and server use to communicate. This class keeps track of where the client and the server are in their conversation and serves up the server's response to the client's statements. The KnockKnockServer object contains the text of all the jokes and makes sure that the client gives the proper response to the server's statements. It wouldn't do to have the client say "Dexter who?" when the server says "Knock! Knock!"

All client/server pairs must have some protocol by which they speak to each other; otherwise, the data that passes back and forth would be meaningless. The protocol that your own clients and servers use depends entirely on the communication required by them to accomplish the task.

The Knock Knock Client

The KnockKnockClient class implements the client program that speaks to the KnockKnockServer. KnockKnockClient is based on the EchoClient program in the previous section, Reading from and Writing to a Socket and should be somewhat familiar to you. But we'll go over the program anyway and look at what's happening in the client in the context of what's going on in the server.

When you start the client program, the server should already be running and listening to the port, waiting for a client to request a connection. So, the first thing the client program does is to open a socket that is connected to the server running on the hostname and port specified:

kkSocket = new Socket("taranis", 4444);

out = new PrintWriter(kkSocket.getOutputStream(), true);

in = new BufferedReader(new InputStreamReader(

kkSocket.getInputStream()));

When creating its socket, KnockKnockClient uses the host name taranis, the name of a hypothetical machine on our network. When you type in and run this program, change the host name to the name of a machine on your network. This is the machine on which you will run the KnockKnockServer.

The KnockKnockClient program also specifies the port number 4444 when creating its socket. This is a remote port number--the number of a port on the server machine--and is the port to which KnockKnockServer is listening. The client's socket is bound to any available local port--a port on the client machine. Remember that the server gets a new socket as well. That socket is bound to local port number 4444 on its machine. The server's socket and the client's socket are connected.

Next comes the while loop that implements the communication between the client and the server. The server speaks first, so the client must listen first. The client does this by reading from the input stream attached to the socket. If the server does speak, it says "Bye." and the client exits the loop. Otherwise, the client displays the text to the standard output and then reads the response

Page 33: Java Set 1

from the user, who types into the standard input. After the user types a carriage return, the client sends the text to the server through the output stream attached to the socket.

while ((fromServer = in.readLine()) != null) {

System.out.println("Server: " + fromServer);

if (fromServer.equals("Bye."))

break;

fromUser = stdIn.readLine();

if (fromUser != null) {

System.out.println("Client: " + fromUser);

out.println(fromUser);

}

}

The communication ends when the server asks if the client wishes to hear another joke, the client says no, and the server says "Bye."

In the interest of good housekeeping, the client closes its input and output streams and the socket:

out.close();

in.close();

stdIn.close();

kkSocket.close();

Running the Programs

You must start the server program first. To do this, run the server program using the Java interpreter, just as you would any other Java application. Remember to run the server on the machine that the client program specifies when it creates the socket.

Next, run the client program. Note that you can run the client on any machine on your network; it does not have to run on the same machine as the server.

If you are too quick, you might start the client before the server has a chance to initialize itself and begin listening on the port. If this happens, you will see a stack trace from the client. If this happens, just restart the client.

Page 34: Java Set 1

If you forget to change the host name in the source code for the KnockKnockClient program, you will see the following error message:

Don't know about host: taranis

To fix this, modify the KnockKnockClient program and provide a valid host name for your network. Recompile the client program and try again.

If you try to start a second client while the first client is connected to the server, the second client just hangs. The next section, Supporting Multiple Clients, talks about supporting multiple clients.

When you successfully get a connection between the client and server, you will see the following text displayed on your screen:

Server: Knock! Knock!

Now, you must respond with:

Who's there?

The client echoes what you type and sends the text to the server. The server responds with the first line of one of the many Knock Knock jokes in its repertoire. Now your screen should contain this (the text you typed is in bold):

Server: Knock! Knock!

Who’s there?

Client: Who's there?

Server: Turnip

Now, you respond with:

Turnip who?"

Again, the client echoes what you type and sends the text to the server. The server responds with the punch line. Now your screen should contain this:

Server: Knock! Knock!

Who’s there?

Client: Who's there?

Server: Turnip

Turnip who?

Client: Turnip who?

Server: Turnip the heat, it's cold in here! Want another? (y/n)

Page 35: Java Set 1

If you want to hear another joke, type y; if not, type n. If you type y, the server begins again with "Knock! Knock!" If you type n, the server says "Bye." thus causing both the client and the server to exit.

If at any point you make a typing mistake, the KnockKnockServer object catches it and the server responds with a message similar to this:

Server: You're supposed to say "Who's there?"!

The server then starts the joke over again:

Server: Try again. Knock! Knock!

Note that the KnockKnockProtocol object is particular about spelling and punctuation but not about capitalization.

Supporting Multiple Clients

To keep the KnockKnockServer example simple, we designed it to listen for and handle a single connection request. However, multiple client requests can come into the same port and, consequently, into the same ServerSocket. Client connection requests are queued at the port, so the server must accept the connections sequentially. However, the server can service them simultaneously through the use of threads - one thread per each client connection.

The basic flow of logic in such a server is this:

while (true) {

accept a connection ;

create a thread to deal with the client ;

end while

The thread reads from and writes to the client connection as necessary.

6. Define RMI. Define the architecture of RMI invocation.

Distributed applications are applications that execute across multiple host system. Objects executing on one host system can invoke the methods of objects on remote hosts. The remotely invoked methods can return values to the local objects.

There are different approaches used for developing distributed applications. The Internet and the Web are examples of distributed systems that have been developed using the Client/Server approach.

The transfer of data is one of the most important processes in distributed applications. The default implementation of the message passing method in Java transfers data from the calling object to the called object within a single Java Virtual Machine (JVM). You have learned how to

Page 36: Java Set 1

cross process boundaries to transfer the data from one host to the other using sockets. Another way to achieve the same in using Remote Method Invocation (RMI), which allows objects in different hosts to send and receive messages. Both the methods achieve the same goal. However, the method calls approach used by RMI in much easier to use.

RMI allows objects in different JVMs belonging to different hosts to send and receive message.

RMI Terminology

RMI is built upon the specification of how local and remote objects interoperate. Local objects are objects that execute on the local machine. Remote objects are objects that execute on all the other machines. Objects on remote hosts are exported so that they can be invoked remotely. An object exports itself by registering itself with a Remote Registry Server. A Remote Registry Server is a service that runs on a server and helps the objects on other hosts to remotely access its registered objects. The registry service maintains a database of all the named remote objects.

A Distributed Application Created Using RMI

Objects that are exported for remote access must implement the interface RemoteInterface. This interface identifies the object to be accessed remotely. All the methods that are to be invoked remotely must throw a RemoteException. The exception is used to handle the errors that may occur during the invocation of a remote method.

Java’s RMI approach is organized into a client/server framework. A local object that invokes a method of a remote object is referred to as a client object, and the remote object whose methods are invoked is referred to as a server object.

Java’s RMI approach makes use of stubs and skeletons. A stubs is a local object on the client’s machine that acts as a proxy for a remote object. The stub provides the methods of the remote object. Local objects invoke the methods of the stubs as if they were methods of the remote objects. The stub communicates this method invocation to the remote object through a skeleton that is implemented on a remote host. The skeleton is the proxy of the client machine’s object that is located on the remote host.

Page 37: Java Set 1

RMI applications often comprise two separate programs, a server and a client. A typical server program creates some remote objects, makes references to these objects accessible, and waits for clients to invoke methods on these objects. A typical client program obtains a remote reference to one or more remote objects on a server and then invokes methods on them. RMI provides the mechanism by which the server and the client communicate and pass information back and forth. Such an application is sometimes referred to as a distributed object application.

Distributed object applications need to do the following:

Locate remote objects: Applications can use various mechanisms to obtain references to remote objects. For example, an application can register its remote objects with RMI's simple naming facility, the RMI registry. Alternatively, an application can pass and return remote object references as part of other remote invocations.

Communicate with remote objects: Details of communication between remote objects are handled by RMI. To the programmer, remote communication looks similar to regular Java method invocations.

Load class definitions for objects that are passed around: Because RMI enables objects to be passed back and forth, it provides mechanisms for loading an object's class definitions as well as for transmitting an object's data.

The following illustration depicts an RMI distributed application that uses the RMI registry to obtain a reference to a remote object. The server calls the registry to associate (or bind) a name with a remote object. The client looks up the remote object by its name in the server's registry and then invokes a method on it. The illustration also shows that the RMI system uses an existing web server to load class definitions, from server to client and from client to server, for objects when needed.

Page 38: Java Set 1

Advantages of Dynamic Code Loading

One of the central and unique features of RMI is its ability to download the definition of an object's class if the class is not defined in the receiver's Java virtual machine. All of the types and behavior of an object, previously available only in a single Java virtual machine, can be transmitted to another, possibly remote, Java virtual machine. RMI passes objects by their actual classes, so the behavior of the objects is not changed when they are sent to another Java virtual machine. This capability enables new types and behaviors to be introduced into a remote Java virtual machine, thus dynamically extending the behavior of an application. The compute engine example in this trail uses this capability to introduce new behavior to a distributed program.

Remote Interfaces, Objects, and Methods

Like any other Java application, a distributed application built by using Java RMI is made up of interfaces and classes. The interfaces declare methods. The classes implement the methods declared in the interfaces and, perhaps, declare additional methods as well. In a distributed application, some implementations might reside in some Java virtual machines but not others. Objects with methods that can be invoked across Java virtual machines are called remote objects.

An object becomes remote by implementing a remote interface, which has the following characteristics:

A remote interface extends the interface java.rmi.Remote. Each method of the interface declares java.rmi.RemoteException in its throws clause, in addition to any application-specific exceptions.

RMI treats a remote object differently from a non-remote object when the object is passed from one Java virtual machine to another Java virtual machine. Rather than making a copy of the implementation object in the receiving Java virtual machine, RMI passes a remote stub for a remote object. The stub acts as the local representative, or proxy, for the remote object and

Page 39: Java Set 1

basically is, to the client, the remote reference. The client invokes a method on the local stub, which is responsible for carrying out the method invocation on the remote object.

A stub for a remote object implements the same set of remote interfaces that the remote object implements. This property enables a stub to be cast to any of the interfaces that the remote object implements. However, only those methods defined in a remote interface are available to be called from the receiving Java virtual machine.

Creating Distributed Applications by Using RMI

Using RMI to develop a distributed application involves these general steps:

1. Designing and implementing the components of your distributed application.

2. Compiling sources.

3. Making classes network accessible.

4. Starting the application.

Designing and Implementing the Application Components

First, determine your application architecture, including which components are local objects and which components are remotely accessible. This step includes:

Defining the remote interfaces: A remote interface specifies the methods that can be invoked remotely by a client. Clients program to remote interfaces, not to the implementation classes of those interfaces. The design of such interfaces includes the determination of the types of objects that will be used as the parameters and return values for these methods. If any of these interfaces or classes do not yet exist, you need to define them as well.

Implementing the remote objects: Remote objects must implement one or more remote interfaces. The remote object class may include implementations of other interfaces and methods that are available only locally. If any local classes are to be used for parameters or return values of any of these methods, they must be implemented as well.

Implementing the clients: Clients that use remote objects can be implemented at any time after the remote interfaces are defined, including after the remote objects have been deployed.

Compiling Sources

As with any Java program, you use the javac compiler to compile the source files. The source files contain the declarations of the remote interfaces, their implementations, any other server classes, and the client classes.

Page 40: Java Set 1

Note: With versions prior to Java Platform, Standard Edition 5.0, an additional step was required to build stub classes, by using the rmic compiler. However, this step is no longer necessary.

Making Classes Network Accessible

In this step, you make certain class definitions network accessible, such as the definitions for the remote interfaces and their associated types, and the definitions for classes that need to be downloaded to the clients or servers. Classes definitions are typically made network accessible through a web server.

Starting the Application

Starting the application includes running the RMI remote object registry, the server, and the client.

The rest of this section walks through the steps used to create a compute engine.

Building a Generic Compute Engine

This trail focuses on a simple, yet powerful, distributed application called a compute engine. The compute engine is a remote object on the server that takes tasks from clients, runs the tasks, and returns any results. The tasks are run on the machine where the server is running. This type of distributed application can enable a number of client machines to make use of a particularly powerful machine or a machine that has specialized hardware.

The novel aspect of the compute engine is that the tasks it runs do not need to be defined when the compute engine is written or started. New kinds of tasks can be created at any time and then given to the compute engine to be run. The only requirement of a task is that its class implements a particular interface. The code needed to accomplish the task can be downloaded by the RMI system to the compute engine. Then, the compute engine runs the task, using the resources on the machine on which the compute engine is running.

The ability to perform arbitrary tasks is enabled by the dynamic nature of the Java platform, which is extended to the network by RMI. RMI dynamically loads the task code into the compute engine's Java virtual machine and runs the task without prior knowledge of the class that implements the task. Such an application, which has the ability to download code dynamically, is often called a behavior-based application. Such applications usually require full agent-enabled infrastructures. With RMI, such applications are part of the basic mechanisms for distributed computing on the Java platform.