UNIT 2
RMI (Remote Method Invocation) AND creating stubs and skeletons
The RMI (Remote Method Invocation) is an API that provides a mechanism to create
distributed application in java. The RMI allows an object to invoke methods on an object
running in another JVM.
The RMI provides remote communication between the applications using two
objects stub and skeleton.
Understanding stub and skeleton
RMI uses stub and skeleton object for communication with the remote object.
A remote object is an object whose method can be invoked from another JVM. Let's
The stub is an object, acts as a gateway for the client side. All the outgoing requests are
routed through it. It resides at the client side and represents the remote object. When the
caller invokes method on the stub object, it does the following tasks:
1. It initiates a connection with remote Virtual Machine (JVM),
2. It writes and transmits (marshals) the parameters to the remote Virtual Machine
(JVM),
3. It waits for the result
4. It reads (unmarshals) the return value or exception, and
5. It finally, returns the value to the caller.
Skeleton
The skeleton is an object, acts as a gateway for the server side object. All the incoming
requests are routed through it. When the skeleton receives the incoming request, it does
the following tasks:
1. It reads the parameter for the remote method
2. It invokes the method on the actual remote object, and
3. It writes and transmits (marshals) the result to the caller.
Understanding requirements for the distributed applications
If any application performs these tasks, it can be distributed application.
1. The application need to locate the remote method
2. It need to provide the communication with the remote objects, and
3. The application need to load the class definitions for the objects.
The RMI application have all these features, so it is called the distributed application.
Example: Simple RMI Program (Addition)
1️⃣ Remote Interface
import [Link];
import [Link];
public interface AddInterface extends Remote {
int add(int a, int b) throws RemoteException;
}
2️⃣ Implementation Class
import [Link];
import [Link];
public class AddImplementation extends UnicastRemoteObject implements AddInterface {
AddImplementation() throws RemoteException {
super();
}
public int add(int a, int b) throws RemoteException {
return a + b;
}
}
3️⃣ RMI Server Program
import [Link];
import [Link];
public class AddServer {
public static void main(String[] args) {
try {
AddImplementation obj = new AddImplementation();
Registry registry = [Link](1099);
[Link]("AddService", obj);
[Link]("Server is ready...");
} catch (Exception e) {
[Link](e);
}
}
}
4️⃣ RMI Client Program
import [Link];
import [Link];
public class AddClient {
public static void main(String[] args) {
try {
Registry registry = [Link]("localhost", 1099);
AddInterface stub = (AddInterface) [Link]("AddService");
[Link]("Result: " + [Link](10, 20));
} catch (Exception e) {
[Link](e);
}
}
}
Output
Server Side:
Server is ready...
Client Side:
Result: 30
DISTRIBUTED APPLICATION ARCHITECTURE
Distributed application architecture is a design approach for developing software
applications that are comprised of multiple components or services that are deployed
and run on multiple computers or servers. This architecture allows for scalability, fault-
tolerance, and easy integration of different components
There are several key aspects of distributed application architecture:
Client-server model:
The application is divided into a client component that interacts with the user and
a server component that provides services and resources. Clients communicate with
servers over a network, typically using protocols like HTTP or TCP/IP.
Middleware:
Middleware is a software layer that sits between the client and server components,
providing services such as message passing, data persistence, and load balancing. It
coordinates communication between different components and facilitates
interoperability.
Service-oriented architecture (SOA):
This architectural style focuses on organizing software applications into services,
which are self-contained modules that provide specific functions or processes. Services
can be developed and deployed independently, and can communicate with each other to
form a complete application.
Micro services architecture:
This approach breaks down the application into smaller, loosely coupled services
that can be developed, deployed, and scaled independently. Each microservice is
responsible for a specific functionality and can communicate with each other through
lightweight APIs.
Message-based communication:
In a distributed application, components typically communicate with each other
through messages. This can be achieved using messaging protocols like AMQP or event-
driven architectures, where components publish and subscribe to events.
Load balancing and fault tolerance:
Distributed applications often involve multiple instances of a component running
on different servers. Load balancing ensures that requests are distributed evenly across
these instances, improving performance and scalability. Fault tolerance mechanisms like
redundancy and failover ensure that the application can continue functioning even if one
or more components fail.
In distributed architecture, components are presented on different platforms and several
components can cooperate with one another over a communication network in order to
achieve a specific objective or goal.
1. In this architecture, information processing is not confined to a single machine
rather it is distributed over several independent computers.
2. A distributed system can be demonstrated by the client-server architecture which
forms the base for multi-tier architectures; alternatives are the broker architecture
such as CORBA, and the Service-Oriented Architecture (SOA).
3. There are several technology frameworks to support distributed architectures,
including .NET, J2EE, CORBA, .NET Web services, AXIS Java Web services, and
Globus Grid services.
4. Middleware is an infrastructure that appropriately supports the development and
execution of distributed applications. It provides a buffer between the applications
and the network.
5. It sits in the middle of system and manages or supports the different components
of a distributed system. Examples are transaction processing monitors, data
convertors and communication controllers etc.
Middleware as an infrastructure for distributed system
The basis of a distributed architecture is its transparency, reliability, and availability.
TYPES OF ARCHITECTURE:
2 trier architecture
The client-server architecture is the most common distributed system architecture which decomposes the system into
two major subsystems or logical processes −
Client − This is the first process that issues a request to the second process i.e. the server.
Server − This is the second process that receives the request, carries it out, and sends a reply to the client.
In this architecture, the application is modelled as a set of services that are provided by servers and a set of clients
that use these services. The servers need not know about clients, but the clients must know the identity of servers,
and the mapping of processors to processes is not necessarily 1 : 1
Client-server Architecture can be classified into two models based on the functionality of the client −
3 trier architecture
In thin-client model, all the application processing and data management is carried by the server. The client
is simply responsible for running the presentation software.
Used when legacy systems are migrated to client server architectures in which legacy system acts as a server in
its own right with a graphical interface implemented on a client
A major disadvantage is that it places a heavy processing load on both the server and the network.
Multi-Tier Architecture (n-tier Architecture)
Multi-tier architecture is a clientserver architecture in which the functions such as presentation, application
processing, and data management are physically separated. By separating an application into tiers, developers obtain
the option of changing or adding a specific layer, instead of reworking the entire application. It provides a model by
which developers can create flexible and reusable applications.
The most general use of multi-tier architecture is the three-tier architecture. A three-tier architecture is typically
composed of a presentation tier, an application tier, and a data storage tier and may execute on a separate processor.
Presentation Tier
Presentation layer is the topmost level of the application by which users can access directly such as webpage or
Operating System GUI (Graphical User interface). The primary function of this layer is to translate the tasks and
results to something that user can understand. It communicates with other tiers so that it places the results to the
browser/client tier and all other tiers in the network.
Application Tier (Business Logic, Logic Tier, or Middle Tier)
Application tier coordinates the application, processes the commands, makes logical decisions, evaluation, and
performs calculations. It controls an applications functionality by performing detailed processing. It also moves and
processes data between the two surrounding layers.
Data Tier
In this layer, information is stored and retrieved from the database or file system. The information is then passed
back for processing and then back to the user. It includes the data persistence mechanisms (database servers, file
shares, etc.) and provides API (Application Programming Interface) to the application tier which provides methods
of managing the stored data.
REMOTE OBJECTS
Now that you have a basic idea of how Java RMI works, we can explore the details of creating and using
distributed objects with RMI. As I mentioned earlier, defining a remote RMI object involves specifying a remote interface
for the object, then providing a class that implements this interface. The remote interface and implementation class are
then used by RMI to generate a client stub and server skeleton for your remote object. The communication between local
objects and remote objects is handled using these client stubs and server skeletons. The relationships among stubs,
skeletons, and the objects that use them are shown
Relationships among remote object, stub, and skeleton classes
When a client gets a reference to a remote object (details on how this reference is
obtained come later) and then calls methods on this object reference, there needs to be a
way for the method request to get transmitted back to the actual object on the remote
server and for the results of the method call to get transmitted back to the client. This is
what the generated stub and skeleton classes are for. They act as the communication link
between the client and your exported remote object, making it seem to the client that the
object actually exists within its Java VM.
Remote objects are objects in a distributed computing environment that can be accessed and manipulated across
different machines or network nodes.
These objects provide a way for software components to communicate and interact with each other over a
network, regardless of their physical locations.
Interface:
Remote objects define interfaces that specify the methods and attributes that can
be accessed remotely. The interface acts as a contract between the client and the remote
object, ensuring that both parties understand how to interact with each other.
Marshaling:
Remote objects utilize marshaling or serialization techniques to convert method
calls, argument values, and return values into a format that can be transmitted over the
network. This ensures that the objects can be properly transported across different
machines and platforms.
Location transparency:
Remote objects enable transparent access to their methods and properties, hiding
the complexities of the underlying network and communication protocols. This allows
clients to invoke remote methods as if they were invoking local methods, simplifying the
development and maintenance of distributed systems.
Remote object reference:
Remote objects are typically accessed through remote object references, which
provide a means of identifying and locating the objects in a distributed system. These
references are used by clients to establish a communication channel with the remote
object and invoke its methods.
import [Link];
import [Link];
public class ThisOrThatServerImpl
extends UnicastRemoteObject implements ThisOrThatServer {
public ThisOrThatServerImpl() throws RemoteException {}
// Remotely accessible methods
public String doThis(String todo) throws RemoteException {
return doSomething("this", todo);
}
public String doThat(String todo) throws RemoteException {
return doSomething("that", todo);
}
// Non-remote methods
private String doSomething(String what, String todo) {
String result = "Did " + what + " to " + todo + ".";
return result;
}
}
Remote Object
RemoteObject implements both the Remote and [Link] package, it is used
by both the Serializable interfaces. Although the RemoteObject class is in the client and
server portions of a remote object reference. Both client stubs and server implementations
are subclassed (directly or indirectly) from RemoteObject. A RemoteObject contains the
remote reference for a particular remote object.
RemoteObject is an abstract class that reimplements the equals (), hashCode(), and
toString() methods inherited from Object in a way that makes sense and is practical for
remote objects. The equals() method, for example, is implemented to return true if the
internal remote references of the two RemoteObject objects are equal, (i.e., if they both
point to the same server object).
Remote Server
RemoteServer is an abstract class that extends RemoteObject. It defines a set of static
methods that are useful for implementing server objects in RMI, and it acts as a base class
for classes that define various semantics for remote objects. In principle, a remote object
can behave according to a simple point-to-point reference scheme; it can have replicated
copies of itself scattered across the network that need to be kept synchronized; or any
number of other scenarios. JDK 1.1 supported only point-to-point, nonpersistent remote
references with the UnicastRemoteObject class. The Java 2 SDK 1.2 has introduced the RMI
activation system, so it provides another subclass of RemoteServer, Activatable.
REMOTE OBJECT ACTIVATION
Remote Object Activation is an advanced feature of Java RMI (Remote Method Invocation) that enables remote objects
to be created and executed only when they are actually needed by a client. Unlike traditional RMI objects that must
remain active throughout the server’s lifetime, activated objects are started on demand, making the system more
efficient and scalable
Starting out with activation
None of the activation tutorials should be the first material you read on RMI. If you
have never used RMI before, you should take a look at Getting Started before you
try these. The first three activation tutorials are intended for developers who have
had some experience developing Java programs that access remote objects by
means of the RMI classes provided as part of the Java 2 SDK.
Going further with activation
This next tutorial on using a Marshalled Object is intended for developers who
have gone through at least one of the first three activation tutorials. More tutorials
may be added to this section in a future release, based on your feedback.
Creating an Activatable Object
Prior to the release of the JavaTM 2 SDK, an instance of a UnicastRemoteObject could be
accessed from a server program that (1) created an instance of the remote object, and (2)
ran all the time. Now with the introduction of the class [Link] and
the RMI daemon, rmid, programs can be written to register information about remote
object implementations that should be created and execute "on demand," rather than
running all the time. The RMI daemon, rmid, provides a Java virtual machine* (JVM) from
which other JVM instances may be spawned.
Working of Remote Object Activation
Step-by-Step Flow:
1. Server registers an activatable object with the activation system
2. Activation system stores object information (descriptor)
3. Client calls a remote method
4. If object is not active:
Activation system starts the object
5. Method call is forwarded to the activated object
6. After some time of inactivity:
Object may be deactivated automatically
import [Link].*;
import [Link].*;
public class HelloImpl extends Activatable implements Hello {
// Constructor used during activation
public HelloImpl(ActivationID id, MarshalledObject<?> data)
throws RemoteException {
super(id, 0);
}
// Remote method
public String sayHello() throws RemoteException {
return "Hello from Activated Object";
}
}
OBJECT SERIALIZATION AND DESERIALIZATION IN JAVA
Serialization in Java is a mechanism for writing an object's state into a byte stream. It is mainly used in Hibernate,
RMI, JPA, EJB, and JMS technologies.
The reverse operation of serialization is called deserialization, where the byte stream is converted into an object. The
serialization and deserialization process is platform-independent. It means we can serialize an object on one platform
and deserialize it on a different platform.
For serializing the object, we call the writeObject() method of the ObjectOutputStream class, and for deserialization,
we call the readObject() method of the ObjectInputStream class.
Java's serialization feature transforms an object into a stream of bytes, making it easier to store or send over a
network. Many different technologies, including Hibernate, RMI (Remote Method Invocation), JPA (Java
Persistence API), EJB (Enterprise JavaBeans), and JMS (Java Message Service), heavily utilize this method.
We must implement the Serializable interface for serializing the object.
Advantages of Java Serialization
It is mainly used to travel object's state on the network (that is known as marshalling).
1. Platform Independence: There are no compatibility problems when transferring serialized objects between
separate Java virtual machines (JVMs) running on different platforms. Java Serialization is an effective
technique for inter-system communication because of its platform independence.
2. Network Communication: Java Serialization facilitates the transmission of object data over a network. This
process, known as marshalling, allows objects to be serialized into a byte stream and sent across a network to
be reconstructed on another machine. It is crucial for applications involving distributed systems, such as
client-server architectures and web services.
[Link]
import [Link];
public class Student implements Serializable{
int id;
String name;
public class TestStudent {
public static void main(String[] args) {
Student s = new Student();
id=101
name=aaa
[Link]("ID: " + [Link]);
[Link]("Name: " + [Link]);
}
}
Output:
101
aaa
Explanation
This code defines a Java class named Student, implementing the Serializable interface. The Serializable interface
serves as a marker, indicating that instances of the Student class can be serialized, meaning their state can be
converted into a byte stream for storage or transmission.
The student class has two instance variables, id, and name, representing the student's ID and name, respectively. It
also includes a constructor that initializes these variables with values passed as arguments. By implementing
Serializable, instances of the Student class can be seamlessly serialized and deserialized, making them suitable for
use in scenarios such as object persistence or network communication.
JAVASPACES
javaSpaces is a distributed shared memory model used for communication and coordination among distributed
Java programs. It is a part of Jini technology and allows processes to interact by placing objects into a shared space
instead of communicating directly with each other. This approach provides loose coupling, scalability, and
simplicity in distributed systems.
The JavaSpaces service specification lists the following design goals for the JavaSpaces
Technology:
It should provide a platform that simplifies the design and implementation of
distributed computing systems.
The client side should have few classes, both to keep the client simple and to speed the downloading of client
classes.
The client side should have a small footprint because it will run on computers with
limited local memory.
A variety of implementations should be possible.
It should be possible to create a replicated JavaSpaces service.
They are designed for a different purpose than either relational or object databases.
Although a JavaSpaces service functions somewhat like a file system and somewhat like a
database, it is neither. The key differences between JavaSpaces technology and databases
are the following:
Relational databases - understand the data they store and manipulate it directly
through query languages such as SQL. JavaSpaces services, on the other hand, store
entries that they understand only by type and the serialized form of each field. As a
result, there are no general queries in the JavaSpaces application design, only "exact
match" or "don't care" for a given field.
Object databases - provide an object-oriented image of stored data that can be modified and used, almost as
if it were transient memory. JavaSpaces systems do not provide a nearly transparent persistent or transient layer, and
they work only on copies of entries.
write(): Writes new objects into a space
take(): Retrieves objects from a space
read(): Makes a copy of objects in a space
Code Sample 1: [Link]
import [Link].*;
public class MessageEntry implements Entry {
public String content;
public MessageEntry() {
public MessageEntry(String content) {
[Link] = content;
public String toString() {
return "MessageContent: " + content;
MessageEntryspace
JavaSpace space = getSpace();
MessageEntry msg = new MessageEntry();
[Link] = "Hello there";
[Link](msg, null, [Link]);
nullTransaction
The write() operation places a copy of an entry into the given JavaSpace service,
and the Entry passed is not affected by the operation. Each write() operation places a
new Entry into the space even if the same Entry object is used in more than one write().
Entries written in a space are governed by a renewable lease. If you like, you can change
the lease (when the write() operation is invoked) to one hour as follows: >
[Link](msg, null, 60 * 60 * 1000);
write()Lease
Once the entry exists in the space, any process with access to the space can perform
a read() on it. To read an entry, a template is used, which is an entry that may have one or
more of its fields set to null. An entry matches a template if (a) the entry has the same
type as or is a subtype of the template and (b) if for every specified non- null field in the
template, their fields match exactly. The null fields act as wildcards and match any value.
The following code segment shows how to create a template and perform a read() on the
space: