You are on page 1of 26

August 2010

Master of Computer Application (MCA) – Semester 4


MC0078 – Java Programming – 4 Credits
(Book ID: B0831 & B0832)
1. Define RMI. Define the architecture of RMI invocation.
ANS:-
Introduction to RMI
RMI is the distributed object system that is built into the core Java environment. You can think of RMI as a
built-in facility for Java that allows you to interact with objects that are actually running in Java virtual
machines on remote hosts on the network. With RMI (and other distributed object APIs we discuss in this
book), you can get a reference to an object that "lives" in a remote process and invoke methods on it as if it
were a local object running within the same virtual machine as your code (hence the name, "Remote Method
Invocation API").
RMI was added to the core Java API in Version 1.1 of the JDK (and enhanced for Version 1.2 of the Java 2
platform), in recognition of the critical need for support for distributed objects in distributed-application
development. Prior to RMI, writing a distributed application involved basic socket programming, where a "raw"
communication channel was used to pass messages and data between two remote processes. Now, with RMI
and distributed objects, you can "export" an object as a remote object, so that other remote processes/agents can
access it directly as a Java object. So, instead of defining a low-level message protocol and data transmission
format between processes in your distributed application, you use Java interfaces as the "protocol" and the
exported method arguments become the data transmission format. The distributed object system (RMI in this
case) handles all the underlying networking needed to make your remote method calls work.
Java RMI is a Java-only distributed object scheme; the objects in an RMI-based distributed application have to
be implemented in Java. Some other distributed object schemes, most notably CORBA, are language-
independent, which means that the objects can be implemented in any language that has a defined binding. With
CORBA, for example, bindings exist for C, C++, Java, Smalltalk, and Ada, among other languages.
The advantages of RMI primarily revolve around the fact that it is "Java-native." Since RMI is part of the core
Java API and is built to work directly with Java objects within the Java VM, the integration of its remote object
facilities into a Java application is almost seamless. You really can use RMI-enabled objects as if they live in
the local Java environment. And since Java RMI is built on the assumption that both the client and server are
Java objects, RMI can extend the internal garbage-collection mechanisms of the standard Java VM to provide
distributed garbage collection of remotely exported objects.
If you have a distributed application with heterogeneous components, some of which are written in Java and
some that aren't, you have a few choices. You can use RMI, wrapping the non-Java code with RMI-enabled
Java objects using the Java Native Interface (JNI). At the end of this chapter, we discuss this first option in
some detail, to give you a feeling for where it could be useful and where it wouldn't. Another option is to use
another object distribution scheme, such as CORBA, that supports language-independent object interfaces.
Chapter 4, "Java IDL", covers the Java interface to CORBA that is included in the Java 2 SDK. A third option
involves the new RMI/IIOP functionality that allows RMI objects to communicate directly with remote
CORBA objects over IIOP. We also discuss this option in some detail at the end of this chapter.
RMI in Action

Before we start examining the details of using RMI, let's look at a simple RMI remote object at work. We can
create an Account object that represents some kind of bank account and then use RMI to export it as a remote
object so that remote clients (e.g., ATMs, personal finance software running on a PC) can access it and carry
out transactions.
The first step is to define the interface for our remote object. Example 3-1 shows the Account interface. You
can tell that it's an RMI object because it extends the java.rmi.Remote interface. Another signal that this is
meant for remote access is that each method can throw a java.rmi.RemoteException. The Account interface
includes methods to get the account name and balance and to make deposits, withdrawals, and transfers.

Example 3-1. A Remote Account Interface

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;

public interface Account extends Remote {


public String getName() throws RemoteException;
public float getBalance() throws RemoteException;
public void withdraw(float amt) throws RemoteException;
public void deposit(float amt) throws RemoteException;
public void transfer(float amt, Account src) throws RemoteException;
public void transfer(List amts, List srcs) throws RemoteException;
}

The next step is to create an implementation of this interface, which leads to the AccountImpl class shown in
Example 3-2. This class implements all the methods listed in the Account interface and adds a constructor that
takes the name of the new account to be created. Notice that the AccountImpl class implements the Account
interface, but it also extends the java.rmi.UnicastRemoteObject class. This RMI class provides some of the
basic remote functionality for server objects.
Example 3-2. Implementation of the Remote Account Interface

import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
import java.util.List;
import java.util.ListIterator;

public class AccountImpl extends UnicastRemoteObject implements Account {


private float mBalance = 0;
private String mName = "";

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


// Create a new account with the given name
public AccountImpl(String name) throws RemoteException {
mName = name;
}

public String getName() throws RemoteException {


return mName;
}
public float getBalance() throws RemoteException {
return mBalance;
}

// Withdraw some funds


public void withdraw(float amt) throws RemoteException {
mBalance -= amt;
// Make sure balance never drops below zero
mBalance = Math.max(mBalance, 0);
}

// Deposit some funds


public void deposit(float amt) throws RemoteException {
mBalance += amt;
}

// Move some funds from another (remote) account into this one
public void transfer(float amt, Account src) throws RemoteException {
src.withdraw(amt);
this.deposit(amt);
}

// Make several transfers from other (remote) accounts into this one
public void transfer(List amts, List srcs) throws RemoteException {
ListIterator amtCurs = amts.listIterator();
ListIterator srcCurs = srcs.listIterator();
// Iterate through the accounts and the amounts to be transferred from
// each (assumes amounts are given as Float objects)
while (amtCurs.hasNext() && srcCurs.hasNext()) {
Float amt = (Float)amtCurs.next();
Account src = (Account)srcCurs.next();
this.transfer(amt.floatValue(), src);

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


}
}
}

Once the remote interface and an implementation of it are complete, you need to compile both Java files with
your favorite Java compiler. After this is done, you use the RMI stub/skeleton compiler to generate a client stub
and a server skeleton for the AccountImpl object. The stub and skeleton handle the communication between the
client application and the server object. With Sun's Java SDK, the RMI compiler is called RMIC, and you can
invoke it for this example like so:
% rmic -d /home/classes AccountImpl
The stub and skeleton classes are generated and stored in the directory given by the -d option (/HOME/CLASSES,
in this case). This example assumes that the AccountImpl class is already in your CLASSPATH before you run
the RMI compiler.
There's just one more thing we need to do before we can actually use our remote object: register it with an RMI
registry, so that remote clients can find it on the network. The utility class that follows, RegAccount, does this
by creating an AccountImpl object and then binding it to a name in the local registry using the
java.rmi.Naming interface. After it's done registering the object, the class goes into a wait(), which allows
remote clients to connect to the remote object:

import java.rmi.Naming;
public class RegAccount {
public static void main(String argv[]) {
try {
// Make an Account with a given name
AccountImpl acct = new AccountImpl("JimF");

// Register it with the local naming registry


Naming.rebind("JimF", acct);
System.out.println("Registered account.");
}
catch (Exception e) {
e.printStackTrace();

}
}
}
After you compile the RegAccount class, you can run its main() method to register an Account with the local
RMI registry. First, however, you need to start the registry. With Sun's Java SDK, the registry can be started
using the RMIREGISTRY utility. On a Unix machine, this can be done like so:
objhost% rmiregistry &

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


Once the registry is started, you can invoke the main() method on the RegAccount class simply by running it:
objhost% java RegAccount
Registered account.
Now we have a remote Account object that is ready and waiting for a client to access it and call its methods.
The following client code does just this, by first looking up the remote Account object using the
java.rmi.Naming interface (and assuming that the Account object was registered on a machine named
OBJHOST.ORG), and then calling the deposit method on the

Account object:

import java.rmi.Naming;

public class AccountClient {


public static void main(String argv[]) {
try {
// Lookup account object
Account jimAcct = (Account)Naming.lookup("rmi://objhost.org/JimF");

// Make deposit
jimAcct.deposit(12000);

// Report results and balance.


System.out.println("Deposited 12,000 into account owned by " +
jimAcct.getName());
System.out.println("Balance now totals: " + jimAcct.getBalance());
}
catch (Exception e) {
System.out.println("Error while looking up account:");
e.printStackTrace();
}
}
}
The first time you run this client, here's what you'd do:
% java AccountClient
Deposited 12,000 into account owned by JimF
Balance now totals: 12000.0
For the sake of this example, I've assumed that the client process is running on a machine with all the necessary
classes available locally (the Account interface and the stub and skeleton classes generated from the
AccountImpl implementation). Later in the chapter, we'll see how to deal with loading these classes remotely
when the client doesn't have them locally.

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


RMI Architecture

Now that we've seen a complete example of an RMI object in action, let's look at what makes remote objects
work, starting with an overview of the underlying RMI architecture. There are three layers that comprise the
basic remote-object communication facilities in RMI:
The STUB/SKELETON layer, which provides the interface that client and server application objects use to
interact with each other.
The REMOTE REFERENCE layer, which is the middleware between the stub/skeleton layer and the underlying
transport protocol. This layer handles the creation and management of remote object references.
The TRANSPORT PROTOCOL layer, which is the binary data protocol that sends remote object requests over the
wire.
These layers interact with each other as shown in Figure 3-1. In this figure, the server is the application that
provides remotely accessible objects, while the client is any remote application that communicates with these
server objects.
In a distributed object system, the distinctions between clients and servers can get pretty blurry at times.
Consider the case where one process registers a remote-enabled object with the RMI naming service, and a
number of remote processes are accessing it. We might be tempted to call the first process the server and the
other processes the clients. But what if one of the clients calls a method on the remote object, passing a
reference to an RMI object that's local to the client. Now the server has a reference to and is using an object
exported from the client, which turns the tables somewhat. The "server" is really the server for one object and
the client of another object, and the "client" is a client and a server, too. For the sake of discussion, I'll refer to a
process in a distributed application as a server or client if its role in the overall system is generally limited to
one or the other. In peer-to-peer systems, where there is no clear client or server, I'll refer to elements of the
system in terms of application-specific roles (e.g., chat participant, chat facilitator).

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


Figure 3-1. The RMI runtime architecture

As you can see in Figure 3-1, a client makes a request of a remote object using a client-side stub; the server
object receives this request from a server-side object skeleton. A client initiates a remote method invocation by
calling a method on a stub object. The stub maintains an internal reference to the remote object it represents and
forwards the method invocation request through the remote reference layer by MARSHALLING the method
arguments into serialized form and asking the remote reference layer to forward the method request and
arguments to the appropriate remote object. Marshalling involves converting local objects into portable form so
that they can be transmitted to a remote process. Each object is checked as it is marshaled, to determine whether
it implements the java.rmi.Remote interface. If it does, its remote reference is used as its marshaled data. If it
isn't a Remote object, the argument is serialized into bytes that are sent to the remote host and reconstituted into
a copy of the local object. If the argument is neither Remote nor Serializable, the stub throws a
java.rmi.MarshalException back to the client.
If the marshalling of method arguments succeeds, the client-side remote reference layer receives the remote
reference and marshaled arguments from the stub. This layer converts the client request into low-level RMI
transport requests according to the type of remote object communication being used. In RMI, remote objects
can (potentially) run under several different communication styles, such as point-to-point object references,

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


replicated objects, or multicast objects. The remote reference layer is responsible for knowing which
communication style is in effect for a given remote object and generating the corresponding transport-level
requests. In the current version of RMI (Version 1.2 of Java 2), the only communication style provided out of
the box is point-to-point object references, so this is the only style we'll discuss in this chapter. For a point-to-
point communication, the remote reference layer constructs a single network-level request and sends it over the
wire to the sole remote object that corresponds to the remote reference passed along with the request.
On the server, the server-side remote reference layer receives the transport-level request and converts it into a
request for the server skeleton that matches the referenced object. The skeleton converts the remote request into
the appropriate method call on the actual server object, which involves UNMARSHALLING the method
arguments into the server environment and passing them to the server object. As you might expect,
unmarshalling is the inverse procedure to the marshalling process on the client. Arguments sent as remote
references are converted into local stubs on the server, and arguments sent as serialized objects are converted
into local copies of the originals.
If the method call generates a return value or an exception, the skeleton marshals the object for transport back to
the client and forwards it through the server reference layer. This result is sent back using the appropriate
transport protocol, where it passes through the client reference layer and stub, is unmarshaled by the stub, and is
finally handed back to the client thread that invoked the remote method.
RMI Object Services
On top of its remote object architecture, RMI provides some basic object services you can use in your
distributed application. These include an object naming/registry service, a remote object activation service, and
distributed garbage collection.
3.1.3.1. Naming/registry service
When a server process wants to export some RMI-based service to clients, it does so by registering one or more
RMI-enabled objects with its local RMI registry (represented by the Registry interface). Each object is
registered with a name clients can use to reference it. A client can obtain a stub reference to the remote object
by asking for the object by name through the Naming interface. The Naming.lookup() method takes the fully
qualified name of a remote object and locates the object on the network. The object's fully qualified name is in a
URL-like syntax that includes the name of the object's host and the object's registered name.
It's important to note that, although the Naming interface is a default naming service provided with RMI, the
RMI registry can be tied into other naming services by vendors. Sun has provided a binding to the RMI registry
through the Java Naming and Directory Interface ( JNDI),
Once the lookup() method locates the object's host, it consults the RMI registry on that host and asks for the
object by name. If the registry finds the object, it generates a remote reference to the object and delivers it to the
client process, where it is converted into a stub reference that is returned to the caller. Once the client has a
remote reference to the server object, communication between the client and the server commences as described
earlier. We'll talk in more detail about the Naming and Registry interfaces later in this chapter.

Object activation service

The remote object activation service is new to RMI as of Version 1.2 of the Java 2 platform. It provides a way
for server objects to be started on an as-needed basis. Without remote activation, a server object has to be

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


registered with the RMI registry service from within a running Java virtual machine. A remote object registered
this way is only available during the lifetime of the Java VM that registered it. If the server VM halts or crashes
for some reason, the server object becomes unavailable and any existing client references to the object become
invalid. Any further attempts by clients to call methods through these now-invalid references result in RMI
exceptions being thrown back to the client.
The RMI activation service provides a way for a server object to be activated automatically when a client
requests it. This involves creating the server object within a new or existing virtual machine and obtaining a
reference to this newly created object for the client that caused the activation. A server object that wants to be
activated automatically needs to register an activation method with the RMI activation daemon running on its
host. We'll discuss the RMI activation service in more detail later in the chapter.

Distributed garbage collection

The last of the remote object services, distributed garbage collection, is a fairly automatic process that you as an
application developer should never have to worry about. Every server that contains RMI-exported objects
automatically maintains a list of remote references to the objects it serves. Each client that requests and receives
a reference to a remote object, either explicitly through the registry/naming service or implicitly as the result of
a remote method call, is issued this remote object reference through the remote reference layer of the object's
host process. The reference layer automatically keeps a record of this reference in the form of an expirable
"lease" on the object. When the client is done with the reference and allows the remote stub to go out of scope,
or when the lease on the object expires, the reference layer on the host automatically deletes the record of the
remote reference and notifies the client's reference layer that this remote reference has expired. The concept of
expirable leases, as opposed to strict on/off references, is used to deal with situations where a client-side failure
or a network failure keeps the client from notifying the server that it is done with its reference to an object.
When an object has no further remote references recorded in the remote reference layer, it becomes a candidate
for garbage collection. If there are also no further local references to the object (this reference list is kept by the
Java VM itself as part of its normal garbage-collection algorithm), the object is marked as garbage and picked
up by the next run of the system garbage collector.

Q. 2 Write the steps in creating and running applets in Java along with a sample program to demonstrate the
same. Also describe various ways of running Applets.
ANS:-

A Java applet is an applet delivered to the users in the form of Java bytecode. Java applets can run in a Web
browser using a Java Virtual Machine (JVM), or in Sun's AppletViewer, a stand-alone tool for testing applets.
Java applets were introduced in the first version of the Java language in 1995. Java applets are usually written in
the Java programming language but they can also be written in other languages that compile to Java bytecode
such as Jython,[8] JRuby,[9] or Eiffel (via SmartEiffel).[10]
Applets are used to provide interactive features to web applications that cannot be provided by HTML alone.
They can capture mouse input (like rotating 3D object) and also have controls like buttons or check boxes. In

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


response to the user action an applet can change the provided graphic content. This makes applets well suitable
for demonstration, visualization and teaching. There are online applet collections for studying various subjects,
from physics[11] to heart physiology.[3] Applets are also used to create online game collections that allow players
to compete against live opponents in real-time.
An applet can also be a text area only, providing, for instance, a cross platform command-line interface to some
remote system.[12] If needed, an applet can leave the dedicated area and run as a separate window. However,
applets have very little control over web page content outside the applet dedicated area, so they are less useful
for improving the site appearance in general (while applets like news tickers[13] or WYSIWYG editors[14] are
also known). Applets can also play media in formats that are not natively supported by the browser[15]
Java applets run at a speed that is comparable to (but generally slower than) other compiled languages such as
C++, but many times faster than JavaScript.[16] In addition they can use 3D hardware acceleration that is
available from Java. This makes applets well suited for non trivial, computation intensive visualizations.
HTML pages may embed parameters that are passed to the applet. Hence the same applet may appear
differently depending on the parameters that were passed. The first implementations involved downloading an
applet class by class. While classes are small files, there are frequently a lot of them, so applets got a reputation
as slow loading components. However, since jars were introduced, an applet is usually delivered as a single file
that has a size of the bigger image (hundreds of kilobytes to several megabytes).
Since Java's bytecode is platform independent, Java applets can be executed by browsers for many platforms,
including Microsoft Windows, Unix, Mac OS and Linux. It is also trivial to run a Java applet as an application
with very little extra code. This has the advantage of running a Java applet in offline mode without the need for
any Internet browser software and also directly from the development IDE.
Many Java developers, blogs and magazines are recommending that the Java Web Start technology be used in
place of Applets.[17][18]
A Java Servlet is sometimes informally compared to be "like" a server-side applet, but it is different in its
language, functions, and in each of the characteristics described here about applets.
Example
The following example is made simple enough to illustrate the essential use of Java applets through its
java.applet package. It also uses classes from the Java Abstract Window Toolkit (AWT) for producing actual
output (in this case, the "Hello, world!" message).
import java.applet.Applet;
import java.awt.*;

// Applet code for the "Hello, world!" example.


// This should be saved in a file named as "HelloWorld.java".
public class HelloWorld extends Applet {
// This method is mandatory, but can be empty (i.e., have no actual code).
public void init() { }

// This method is mandatory, but can be empty.(i.e.,have no actual code).


public void stop() { }

// Print a message on the screen (x=20, y=10).

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


public void paint(Graphics g) {
g.drawString("Hello, world!", 20,10);

// Draws a circle on the screen (x=40, y=30).


g.drawArc(40,30,20,20,0,360);
}
}
More simple applets are available at Wikiversity.[24]
For compilation, this code is saved on a plain-ASCII file with the same name as the class and .java extension,
i.e. HelloWorld.java. The resulting HelloWorld.class applet should be placed on the web server and is
invoked within an HTML page by using an <APPLET> or an <OBJECT> tag. For example:
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>HelloWorld_example.html</TITLE>
</HEAD>
<BODY>
<H1>A Java applet example</H1>
<P>Here it is: <APPLET code="HelloWorld.class" WIDTH="200" HEIGHT="40">
This is where HelloWorld.class runs.</APPLET></P>
</BODY>
</HTML>
Displaying the HelloWorld_example.html page from a Web server, the result should look as this:

A Java applet example


Here it is: Hello, world!

Q. 3 Create a User Interface to perform arithmetic operations to demonstrate event handling mechanisms.

ANS:- The JavaFX Script programming language enables you to make a desktop or a mobile application respond in a
preprogrammed way to events through a convenient event-handling mechanism. Each JavaFX object that can potentially
expose behavior has instance variables that map to event-related functions. You can define these functions to handle
events such as the click of a mouse button, tap of a stylus, or the release of a key. For example, you can define a function
that will render text when you click a circle with your mouse. For a complete list of events that can be handled by objects,
see the JavaFX Script API.
The following screen captures show all the possible button states.

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


Figure 1: States of the Button

Create a file with an .fx extension, for example Events.fx. Avoid using file names that match the names of existing
classes, instance variables, or reserved words because this type of naming leads to errors during compilation. For more
information about existing classes, variables, and reserved words, see JavaFX Script API and Learning the JavaFX Script
Programming Language.
Adding Graphics
All button states are available in the following PNG images: play_onMouseExited.png, play_onMousePressed.png,
stop_onMouseExited.png, and stop_onMousePressed.png. To use the images as scene objects, use a combination of the
Image and ImageView classes.

Add import statements for the Image and ImageView classes.


Define four Image objects corresponding to different states of the button.

When specifying the image url, you can set the URI of the resource or use the relative codebase. In this example, the
image url is set by using the __DIR__ variable that indicates the directory where the image is located. By default it points
to the current directory, so ensure that the images are located in the same directory as application-compiled classes. To run
the application on the mobile emulator ensure that the images are packed into the application jar file along with the
compiled classes.
Define the image variable to store an image of the current button state, and set it to the initial state, playNormal.
Define the button variable to the a scene object corresponding to the current state of the button, and bind it to the image
variable.
Specify the scene of the application and add the button to its content.
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.Group;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


def playNormal = Image { url: "{__DIR__}play_onMouseExited.png"};
def playPressed = Image { url: "{__DIR__}play_onMousePressed.png"};
def stopNormal = Image { url: "{__DIR__}stop_onMouseExited.png"};
def stopPressed = Image { url: "{__DIR__}stop_onMousePressed.png"};

var image = playNormal;

var button = ImageView {image: bind image}

Stage {
title: "Play Button"
scene: Scene {
width: 300
height: 240
content: Group {
content: button
}
}
}

Note: The button is added to the Group construct for further application enhancements. In your application you can add an
ImageView object directly to the scene content..

Handling the Press Event


This application handles three types of mouse events: mouse is pressed, mouse is released, and mouse is dragged. Each of
these events is processed by a specific Node function. Because the ImageView class inherits all Node instance variables
and functions, you can apply the onMousePressed, onMouseReleased, and onMouseDragged function to your button.
The press event happens when you press the button with a stylus or a mouse without releasing it. In this example, the
press event changes the button's appearance.
To handle the mouse press event, perform the following steps.
Define a Boolean variable named mode to fix whether the button is in the Play or Stop mode. Set the true value so that the
button will be in Play mode when the application is started.
Define the X and Y variables to use them for calculating the button's position when processing the drag event.
Use the if construction to check the mode of the button. If it is in Play mode, the image is set to playPressed, and
stopPressed otherwise.
var mode = true; //true for the Play mode,
//false for the Stop mode

var X: Number;
var Y: Number;

onMousePressed: function(event) {

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


X = event.sceneX - event.node.translateX;
Y = event.sceneY - event.node.translateY;
image = if (mode){
playPressed;
} else {
stopPressed;
};
}

As a result, the button changes its appearance when you press it depending on the mode of the button.
Handling the Release Event
The release event occurs when you release a mouse pointer from the button. In this example, when you release the pointer
from the button, it switches its mode.
To handle the mouse release event, use the following code:
onMouseReleased: function(event) {
if (mode){
image = stopNormal;
mode = false;
} else {
image = playNormal;
mode = true;
}
}

After an image is changed, the mode variable changes its value to the opposite. At this point, the application implements
switching between the Play and Stop modes and changing the button appearance on the mouse press. The next section
concerns dragging the button within the scene.
Handling the Drag Event
Unlike the mouse events mentioned in the previous sections, the onMouseDragged event does not change the button's
appearance. This event enables you to alter the button position dragging it when the mouse is pressed. In this example,
you cannot move the button beyond the bounds of the scene.
Use the following code fragment to handle the drag event:
onMouseDragged: function(event) {
if (event.sceneX - X <0) {
event.node.translateX = 0;
} else { if (event.sceneX - X > 300 - image.width){
event.node.translateX = 300 - image.width;
} else {
event.node.translateX = event.sceneX - X;
}
}

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


if (event.sceneY - Y <0) {
event.node.translateY = 0;
} else {if (event.sceneY - Y > 240 - image.height){
event.node.translateY = 240 - image.height;
} else{
event.node.translateY = event.sceneY - Y;
}
}
}

Two if constructions are used to check whether the button has been dragged outside of the scene, and to set values for the
translateX and translateY variables of the button. Consider an example when the drag event occurred at the point (320,
100). Suppose that the X was fixed as 5, and the Y was fixed as 10. Then the event.node.translateX - X = 320 - 5 = 315,
while 300 - image.width = 300 -63 = 237. The value 315 is greater than 237, so the translateX variable will be set to 300 -
image.width = 237, and the button will be placed at the right border of the scene. The translateY variable will be set to
event.sceneY - Y = 100 - 10 = 90. Therefore, the button will be moved to the following position: translateX = 237,
translateY = 90.
The following screen capture shows the application run on the Touch Phone emulator.

Figure 2: Event-Handling Application Run on the Mobile Emulator

You can find the complete code of this application in the EventsCommon.fx file. The next section discusses how to handle
some additional desktop-specific events.
Desktop Profile
- Adding Tooltips
- Handling the Mouse-Enter Event

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


- Handling the Mouse-Exit Event

In this section, you will learn how to enhance the existing example by using additional features specific for desktop
applications. Consider handling the mouse-enter and mouse-exit events by changing the button's appearance when the
mouse pointer is on it. In addition, the modified application will show two variants of tooltips depending in the mode of
the button. Try the following applet to evaluate event handling. Hover, press, release, and drag the button.

Two new images represent the button's state: play_onMouseEntered.png and stop_onMouseEntered.png. So you need to
define two more Image variables.

def playHover = Image { url: "{__DIR__}play_onMouseEntered.png"};


def stopHover = Image { url: "{__DIR__}stop_onMouseEntered.png"};

Adding Tooltips
Perform the following steps to create a textual tooltip and add it to the scene.
Add import statements for the Text, Font, Timeline, and Color classes.
Declare a Text object specifying the string to render, the color, and the position of the tooltip. Set the content variable
depending on the current mode of the button. Set "Play Button" when the button is in Play mode, and "Stop Button"
otherwise. Also bind the translateX and translateY variables to the corresponding variables of the button object.
Add the tooltip object to the scene.
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.Group;
import javafx.animation.Timeline;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;

def tooltip = Text {


content: bind if (mode) "Play Button" else "Stop Button"
translateX: bind button.translateX
translateY: bind button.translateY + 80
opacity: 0.0

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


font: Font {
size: 12
name: "Tahoma"
}
fill: Color.BLACK
};

Stage {
title: "Play Button"
scene: Scene {
fill: Color.WHITE
width: 300
height: 240
content: Group {
content: [button, tooltip]
}
}

Handling the Mouse-Enter Event


This event happens when you position the mouse pointer in the button area. This event is controlled by the
onMouseEntered function.
To handle the mouse enter event define the onMouseEntered function. Create a Timeline object to alter the opacity of
tooltips so that they do not appear instantly as you hover the button, but gradually within five seconds. The following code
fragment performs these tasks.
def appear = Timeline {
keyFrames: [
at(0s) {tooltip.opacity => 0.0},
at(0.5s) {tooltip.opacity => 1.0}
]
}

...

onMouseEntered: function(event) {
image = if (mode){
playHover;
} else {
stopHover
}
appear.rate = 1;
appear.play();
}

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


After you enter the button area with the mouse pointer, the playHover or stopHover image appears and an animation
timeline starts adding the tooltip. For more information about the onMouseEntered function, see JavaFX Script API. For
more information about the MouseEvent class, see JavaFX Script API. For more information about animation, see
Creating Animated Objects.
Note: Because a new state was introduced, you need to apply the following code for the onMouseReleased function.
When the mouse is released the button should be in a hovered state, not in the initial state.
onMouseReleased: function(event) {
if (mode){
image = stopHover;
mode = false;
} else {
image = playHover;
mode = true;
}
}

Handling the Mouse-Exit Event


This type of event occurs when the mouse pointer exits the button area. The event is defined by the onMouseExited
function.
To define the mouse-exit event, use the following code:
onMouseExited: function(event) {
image = if (mode){
playNormal;
} else {
stopNormal
}
appear.rate = -1;
appear.play();
}

When the mouse pointer exits the area defined by the graphic button, the button's appearance returns to its initial state.
The tooltip disappears, because the rate variable of the animation timeline is set to -1 and the tooltip opacity alters from
1.0 to 0.0.
For more information about the onMouseExited function, see JavaFX Script API.
Here is the complete Events.fx file.

Q.4. Describe the Web architecture and servlet life cycle.


ANS:-

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


A servlet life cycle can be defined as the entire process from its creation till the destruction. The following are the paths followed by a servlet
The servlet is initialized by calling the init () method.
The servlet calls service() method to process a client's request.
The servlet is terminated by calling the destroy() method.
Finally, servlet is garbage collected by the garbage collector of the JVM.
Now let us discuss the life cycle methods in details.
The init() method :
The init method is designed to be called only once. It is called when the servlet is first created, and not called again for each user request. So, it is used for
one-time initializations, just as with the init method of applets.
The servlet is normally created when a user first invokes a URL corresponding to the servlet, but you can also specify that the servlet be loaded when the
server is first started.
When a user invokes a servlet, a single instance of each servlet gets created, with each user request resulting in a new thread that is handed off to doGet or
doPost as appropriate. The init() method simply creates or loads some data that will be used throughout the life of the servlet.
The init method definition looks like this:
public void init() throws ServletException {
// Initialization code...
}

The service() method :


The service() method is the main method to perform the actual task. The servlet container (i.e. web server) calls the service() method to handle requests
coming from the client( browsers) and to write the formatted response back to the client.
Each time the server receives a request for a servlet, the server spawns a new thread and calls service. The service() method checks the HTTP request type
(GET, POST, PUT, DELETE, etc.) and calls doGet, doPost, doPut, doDelete, etc. methods as appropriate.
Here is the signature of this method:
public void service(ServletRequest request,
ServletResponse response)
throws ServletException, IOException{
}
The service () method is called by the container and service method invokes doGe, doPost, doPut, doDelete, etc. methods as appropriate. So you have nothing
to do with service() method but you override either doGet() or doPost() depending on what type of request you receive from the client.
The doGet() and doPost() are most frequently used methods with in each service request. Here are the signature of these two methods.
The doGet() Method
A GET request results from a normal request for a URL or from an HTML form that has no METHOD specified and it should be handled by doGet() method.
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet code
}
The doPost() Method
A POST request results from an HTML form that specifically lists POST as the METHOD and it should be handled by doPost() method.
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet code
}

The destroy() method :


The destroy() method is called only once at the end of the life cycle of a servlet. This method gives your servlet a chance to close database connections, halt
background threads, write cookie lists or hit counts to disk, and perform other such cleanup activities.
After the destroy() method is called, the servlet object is marked for garbage collection. The destroy method definition looks like this:

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


public void destroy() {
// Finalization code...
}

Architecture Digram:
The following figure depicts a typical servlet life-cycle scenario.
First the HTTP requests coming to the server are delegated to the servlet container.
The servlet container loads the servlet before invoking the service() method.
Then the servlet container handles multiple requests by spawning multiple threads, each thread executing the service() method of a single instance of the
servlet

Book ID: B0832

Q.5. Explain the importance of CORBA and its applications in running client server programs.
ANS:

Exceptions in CORBA IDL: CORBA IDL allows exceptions to be defined in interfaces and thrown by their ethods. To
illustrate this point, we have defined our list of shapes inthe server as a sequence of a fixed length (line 4) and have
defined FullException (line6), which is thrown by the method newShape (line 7) if the client attempts to add a shape when
the sequence is full.
Invocation semantics: Remote invocation in CORBA has at-most-once call semantics as the default. However, IDL may
specify that the invocation of a particular method has maybe semantics by using the oneway keyword. The client does not
block on oneway requests, which can be used only for methods without results. For an example of a
oneway request, see the example on callbacks at the end of Section 17.2.1.
The CORBA Naming service
◊ The CORBA Naming Service is discussed in Section
17.3.1. It is a binder that provides operations including rebind for servers to register the
remote object references of CORBA objects by name and resolve for clients to look them up by name. The names are
structured in a hierarchic fashion, and each name in a path is inside a structure called a NameComponent. This makes
access in a simple example seem rather complex.
CORBA pseudo objects (Jaa 2 version 1.4) ◊ Implementations of CORBA provide some interfaces to the functionality of
the ORB that programmers need to use. They are called pseudo-objects because they cannot be used like CORBA objects;
for example, they cannot be passed as arguments in RMIs. They have IDL interfaces and are implemented as libraries.
Those relevant to our simple example are:
• The ORB interface includes: The method init, which must be called to initialize the ORB; the method
resolve_initial_references, which is used to find services such as the Naming Service and the root POA; other methods,
which enable conversions between remote object references and strings.
• The POA (Portable Object Adaptor – see Figure 17.6 and page 678) interface includes: A method for activating a
POAmanager; a method servant_to_reference for registering a CORBA object.

CORBA client and server example (for Java 2 version 1.4)

This section outlines the steps necessary to produce client and server programs that use the IDL Shape and ShapeList
interfaces shown in Figure 17.1. This is followed by a discussion of callbacks in CORBA. We use Java as the client and

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


server languages, but the approach is similar for other languages. The interface compiler idlj can be applied to the
CORBA interfaces to generate the following items:
• The equivalent Java interfaces – two per IDL interface. For example, the interfaces ShapeListOperations and ShapeList
are shown in Figure 17.2.
• The server skeletons for each idl interface. The names of skeleton classes end in POA, for example ShapeListPOA.
• The proxy classes or client stubs, one for each IDL interface. The names of these classes end in Stub, for example
_ShapeListStub.
CORBA CASE STUDY
• A Java class to correspond to each of the structs defined with the IDL interfaces.
In our example, classes Rectangle and GraphicalObject are generated. Each of
these classes contains a declaration of one instance variable for each field in the
corresponding struct and a pair of constructors, but no other methods.
• Classes called helpers and holders, one for each of the types defined in the IDL
interface. A helper class contains the narrow method, which is used to cast down
from a given object reference to the class to which it belongs, which is lower down
the class hierarchy. For example, the narrow method in ShapeHelper casts down to
class Shape. The holder classes deal with out and inout arguments, which cannot be
mapped directly onto Java. See Exercise 17.9 for an example of the use of holders.
Server program
◊ The server program should contain implementations of one or more
IDL interfaces. For a server written in an object-oriented language such as Java or C++,
these implementations are implemented as servant classes. CORBA objects are
instances of servant classes.
When a server creates an instance of a servant class, it must register it with the
POA, which makes the instance into a CORBA object and gives it a remote object
reference. Unless this is done, it will not be able to receive remote invocations. Readers
who studied Chapter 5 carefully may realize that registering the object with the POA
causes it to be recorded in the CORBA equivalent of the remote object table.
In our example, the server contains implementations of the interfaces Shape and
ShapeList in the form of two servant classes, together with a server class that contains a
initialization section (see Section 5.2.5) in its main method.
The servant classes: Each servant class extends the corresponding skeleton class and
implements the methods of an IDL interface using the method signatures defined in
the equivalent Java interface. The servant class that implements the ShapeList
interface is named ShapeListServant, although any other name could have been
chosen. Its outline is shown in Figure 17.3. Consider the method newShape in line 1,
which is a factory method because it creates Shape objects. To make a Shape object
a CORBA object, it is registered with the POA by means of its servant_to_reference
method, as shown in line 2. Complete versions of the IDL interface and the client and
server classes in this example are available at cdk3.net/corba.
The server: The main method in the server class ShapeListServer is shown in Figure
17.4. It first creates and initializes the ORB (line 1). It gets a reference to the root
Figure 17.2 Java interfaces generated by idlj from CORBA interface ShapeList.
public interface ShapeListOperations {
Shape newShape(GraphicalObject g) throws ShapeListPackage.FullException;

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


Shape[] allShapes();
int getVersion();
}
public interface ShapeList extends ShapeListOperations, org.omg.CORBA.Object,
org.omg.CORBA.portable.IDLEntity { } // interface ShapeList
SECTION 17.2 CORBA RMI 675
POA and activates the POAManager (lines 2 & 3). Then it creates an instance of
ShapeListServant, which is just a Java object (line 4). It then makes it into a CORBA
object by registering it with the POA (line 5). After this, it registers the server with
the Naming Service. It then waits for incoming client requests (line 10).
Servers using the Naming Service first get a root naming context (line 6), then make a
NameComponent (line 7), define a path (line 8) and finally use the rebind method (line
9) to register the name and remote object reference. Clients carry out the same steps but
use the resolve method as shown in Figure 17.5 line 2.
The client program
◊ An example client program is shown in Figure 17.5. It creates and
initializes an ORB (line 1), then contacts the Naming Service to get a reference to the
remote ShapeList object by using its resolve method (line 2). After that it invokes its
method allShapes (line 3) to obtain a sequence of remote object references to all the
Shapes currently held at the server. It then invokes the getAllState method (line 4),
giving as argument the first remote object reference in the sequence returned; the result
is supplied as an instance of the GraphicalObject class.
Figure 17.3 ShapeListServant class of the Java server program for CORBA interface ShapeList
import org.omg.CORBA.*;
import org.omg.PortableServer.POA;
class ShapeListServant extends ShapeListPOA {
private POA theRootpoa;
private Shape theList[];
private int version;
private static int n=0;
public ShapeListServant(POA rootpoa){
theRootpoa = rootpoa;
// initialize the other instance variables
}
public Shape newShape(GraphicalObject g) throws ShapeListPackage.FullException {1
version++; Shape s = null;
ShapeServant shapeRef = new ShapeServant( g, version);
try {
org.omg.CORBA.Object ref = theRoopoa.servant_to_reference(shapeRef); 2
s = ShapeHelper.narrow(ref);
} catch (Exception e) {}
if(n >=100) throw new ShapeListPackage.FullException();
theList[n++] = s;
return s;
}

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


public Shape[] allShapes(){ ... }
public int getVersion() { ... }
}
676 CHAPTER 17 CORBA CASE STUDY
The getAllState method seems to contradict our earlier statement that objects
cannot be passed by value in CORBA, because both client and server deal in instances
of the class GraphicalObject. However, there is no contradiction: the CORBA object
returns a struct, and clients using a different language might see it differently. For
example, in the C++ language the client would see it as a struct. Even in Java, the
generated class GraphicalObject is more like a struct because it has no methods.
Client programs should always catch CORBA SystemExceptions, which report on
errors due to distribution (see line 5). Client programs should also catch the exceptions
defined in the IDL interface, such as the FullException thrown by the newShape method.
This example illustrates the use of the narrow operation: the resolve operation of
the Naming Service returns a value of type Object; this type is narrowed to suit the
particular type required – ShapeList.
Callbacks
◊ Callbacks can be implemented in CORBA in a manner similar to the one
described for Java RMI in Section 5.5.1. For example, the WhiteboardCallback
interface may be defined as follows:
interface WhiteboardCallback {
oneway void callback(in int version);
};
Figure 17.4 Java class ShapeListServer
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
import org.omg.PortableServer.*;
public class ShapeListServer {
public static void main(String args[]) {
try{
ORB orb = ORB.init(args, null); 1
POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));2
rootpoa.the_POAManager().activate(); 3
ShapeListServant shapeRef = new ShapeListServant(rootpoa); 4
org.omg.CORBA.Object ref = rootpoa.servant_to_reference(SLSRef); 5
ShapeList SLRef = ShapeListHelper.narrow(ref);
org.omg.CORBA.ObjectobjRef= orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
NameComponent nc = new NameComponent("ShapeList", ""); 6
NameComponent path[] = {nc}; 7
ncRef.rebind(path, SLRef); 8
orb.run(); 9
} catch (Exception e) { ... }
}

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


}
SECTION 17.2 CORBA RMI 677
This interface is implemented as a CORBA object by the client, enabling the server to
send the client a version number whenever new objects are added. But before the server
can do this, the client needs to inform the server of the remote object reference of its
object. To make this possible, the ShapeList interface requires additional methods such
as register and deregister, as follows:
int register(in WhiteboardCallback callback);
void deregister(in int callbackId);
After a client has obtained a reference to the ShapeList object and created an instance of
WhiteboardCallback, it uses the register method of ShapeList to inform the server that
it is interested in receiving callbacks. The ShapeList object in the server is responsible
for keeping a list of interested clients and notifying all of them each time its version
number increases when a new object is added. The callback method is declared as
oneway so that the server may use asynchronous calls to avoid delay as it notifies each
client.
17.2.2 The architecture of CORBA
The architecture is designed to support the role of an object request broker that enables
clients to invoke methods in remote objects, where both clients and servers can be
implemented in a variety of programming languages. The main components of the
CORBA architecture are illustrated in Figure 17.6.
Figure 17.5 Java client program for CORBA interfaces Shape and ShapeList
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
public class ShapeListClient{
public static void main(String args[]) {
try{
ORB orb = ORB.init(args, null); 1
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
NameComponent nc = new NameComponent("ShapeList", "");
NameComponent path [] = { nc };
ShapeList shapeListRef =
ShapeListHelper.narrow(ncRef.resolve(path)); 2
Shape[] sList = shapeListRef.allShapes(); 3
GraphicalObject g = sList[0].getAllState(); 4
} catch(org.omg.CORBA.SystemException e) {...}
}

Q.7. Explain the importance, applications and working of Ajax.


ANS:-
Importance of Ajax in Web Application

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


Introduction
Web applications are fun to build. They are like the funky airplanes of Web sites. Web applications allow the designer
and developer to get together and solve a problem for their customers that the customers might not have even know
they had. But most Web applications are slow and tedious. Even the fastest of them has lots of free time for your
customers to go get a snack (worst of all) head off to a faster Web site. It's that dreaded hourglass! You click a
process button and the hourglass appears as the Web application consults the server and the server thinks about
what it's going to send back to you.
What is AJAX
The name AJAX is short for Asynchronous JavaScript and XML. It uses the JavaScript XMLHttpRequest function to
create a tunnel from the client's browser to the server and transmit information back and forth without having to
refresh the page. The data travels in XML format because it transmits complex data types over clear text.

AJAX uses XHTML for the data presentation of the view layer, DOM, short for Document Object Model, which
dynamically manipulates the presentation, XML for data exchange, and XMLHttpRequest as the exchange engine that
ties everything together.

Because of these requirements, AJAX works on I.E. 5.0+, Mozilla 1.0+, Firefox 1.0+, Netscape 7.0+, and Apple
added it to Safari 1.2+.

Traditional HTML sends a request to the server, which processes it and either returns a static HTML page or
dispatches the request to some scripting language such as ColdFusion, which creates and returns an HTML page for
the browser to render. When this method has to retrieve new data from the server it has to repost and reload
another HTML file. In many cases perhaps only a small portion of the returned HTML code varies and the shell itself
remains the same resulting in huge overhead because the data has to be downloaded every time.

Some classic examples of applications that would benefit from AJAX are searching for information and displaying it
back in a table, related select dropdowns, or checking if a user exists before submitting an entire form.

As we can see, AJAX offers many advantages over traditional HTML applications, but we shouldn't overestimate it.
Because the data is JavaScript-driven, one of the main drawbacks is that search engines won't index any of the
dynamically generated content. It's definitely not SEO-friendly.

People familiar with MVC will have a better grasp of the concept. Though details of MVC are outside of the scope of
this article, the three defined components are Model, View, and Controller. The controller mediates between the data
model and the view. It responds to events, which are usually actions by users, and changes the view or model as
appropriate. The view consists of the HTML. JavaScript reacts to events triggered by the user and alters the existing
rendered content with DOM. ColdFusion will be our model layer and can consist of one or more files.

Building an AJAX platform or engine from scratch can be a difficult and lengthy procedure. There are many AJAX
engines available for download and you're welcome to use any of them. The only difference between implementations
will be the data encoding, transmission, and decoding methods. The views and models of the MVC will be the same.
My examples will be based on CFAJAX, a community-driven Open Source project. One of the problems with CFAJAX is
its poor documentation. There is no manual or even a complete FAQ. So I will explain how to set it up step-by-step
and work around its downside.

To use AJAX you'll need to really know JavaScript and DOM. But by the end of this article you'll be able to set up
AJAX, a ColdFusion model, make basic calls, and exchange simple data. As the applications grow and become more
complex, the AJAX engine will remain the same, and the CF model will have more functions, but your JavaScript will
have to manipulate more and more objects and that's where it's really at.

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227


Ajax is a way of developing Web applications that combines:
XHTML and CSS standards based presentation
Interaction with the page through the DOM
Data interchange with XML and XSLT
Asynchronous data retrieval with XMLHttpRequest
JavaScript to tie it all together
In the traditional Web application, the interaction between the customer and the server goes like this:
In standard Web applications, Customer accesses Web application
the interaction between the customer and the server is synchronous. This means that one has to happen after the
other. If a customer clicks a link, the request is sent to the server, which then sends the result back.
Server processes request and sends data to the browser while the customer waits
Customer clicks on a link or interacts with the application
Server processes request and sends data back to the browser while the customer waits
etc....
There is a lot of customer waiting.

Why Ajax is widely used in Web Applications


They can use a standard web browser, such as Firefox, Internet Explorer or Safari, as their only user interface.
They don't force the user to wait for the web server every time the user clicks a button. This is what "asynchronous"
means. For instance, gmail fetches new email messages in the background ("asynchronously") without forcing the
user to wait. This makes an AJAX application respond much more like a "real" application on the user's computer,
such as Microsoft Outlook.
The Ajax engine works within the Web browser (through JavaScript and the DOM) to render the Web application and
handle any requests that the customer might have of the Web server. The beauty of it is that because the Ajax
engine is handling the requests, it can hold most information in the engine itself, while allowing the interaction with
the application and the customer to happen as asynchronously and independently of any interaction with the server.
They use standard JavaScript features (including the unofficial XMLHTTPRequest standard, pioneered by Microsoft
and adopted by Firefox and other browsers) to fetch data in the background and display different email messages or
other data "on the fly" when the user clicks on appropriate parts of the interface.
Usually they manipulate data in XML format. This allows AJAX applications to interact easily with server-side code
written in a variety of languages, such as PHP, Perl/CGI, Python and ASP.NET. Using XML isn't absolutely necessary,
and in fact many "AJAX" applications don't -- they use the XMLHTTPRequest object to send and receive data "on the
fly," but they don't actually bother packaging that data as XML.
with Ajax, the JavaScript that is loaded when the page loads handles most of the basic tasks such as data validation
and manipulation, as well as display rendering the Ajax engine handles without a trip to the server. At the same time
that it is making display changes for the customer, it is sending data back and forth to the server. But the data
transfer is not dependent upon actions of the customer.

Chandra Shekhar Singh MCA 4th Sem Roll No. 511021227

You might also like