Java Programming Unit 2
Java Programming Unit 2
Java Programming Unit 2
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.
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
understand the stub and skeleton objects:
stub
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:
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:
The RMI application have all these features, so it is called the distributed application.
For creating the remote interface, extend the Remote interface and declare the
RemoteException with all the methods of the remote interface. Here, we are creating
a remote interface that extends the Remote interface. There is only one method named
add() and it declares RemoteException.
1. import java.rmi.*;
2. public interface Adder extends Remote{
3. public int add(int x,int y)throws RemoteException;
4. }
2) Provide the implementation of the remote interface
Now provide the implementation of the remote interface. For providing the
implementation of the Remote interface, we need to
1. import java.rmi.*;
2. import java.rmi.server.*;
3. public class AdderRemote extends UnicastRemoteObject implements Adder{
4. AdderRemote()throws RemoteException{
5. super();
6. }
7. public int add(int x,int y){return x+y;}
8. }
3) create the stub and skeleton objects using the rmic tool.
Next step is to create stub and skeleton objects using the rmi compiler. The rmic tool
invokes the RMI compiler and creates stub and skeleton objects.
1. rmic AdderRemote
Now start the registry service by using the rmiregistry tool. If you don't specify the
port number, it uses a default port number. In this example, we are using the port
number 5000.
1. rmiregistry 5000
Now rmi services need to be hosted in a server process. The Naming class provides
methods to get and store the remote object. The Naming class provides 5 methods.
public static java.rmi.Remote
lookup(java.lang.String) throws It returns the
java.rmi.NotBoundException, reference of the
java.net.MalformedURLException, remote object.
java.rmi.RemoteException;
public static void bind(java.lang.String,
java.rmi.Remote) throws It binds the remote
java.rmi.AlreadyBoundException, object with the
java.net.MalformedURLException, given name.
java.rmi.RemoteException;
public static void unbind(java.lang.String) It destroys the
throws java.rmi.RemoteException, remote object which
java.rmi.NotBoundException, is bound with the
java.net.MalformedURLException; given name.
public static void rebind(java.lang.String, It binds the remote
java.rmi.Remote) throws java.rmi.RemoteException, object to the new
java.net.MalformedURLException; name.
It returns an array
public static java.lang.String[]
of the names of the
list(java.lang.String) throws
remote objects
java.rmi.RemoteException,
bound in the
java.net.MalformedURLException;
registry.
In this example, we are binding the remote object by the name sonoo.
1. import java.rmi.*;
2. import java.rmi.registry.*;
3. public class MyServer{
4. public static void main(String args[]){
5. try{
6. Adder stub=new AdderRemote();
7. Naming.rebind("rmi://localhost:5000/sonoo",stub);
8. }catch(Exception e){System.out.println(e);}
9. }
10. }
At the client we are getting the stub object by the lookup() method of the Naming
class and invoking the method on this object. In this example, we are running the
server and client applications, in the same machine so we are using localhost. If you
want to access the remote object from another machine, change the localhost to the
host name (or IP address) where the remote object is located.
1. import java.rmi.*;
2. public class MyClient{
3. public static void main(String args[]){
4. try{
5. Adder stub=(Adder)Naming.lookup("rmi://localhost:5000/sonoo");
6. System.out.println(stub.add(34,4));
7. }catch(Exception e){}
8. }
9. }
1. For running this rmi example,
2.
3. 1) compile all the java files
4.
5. javac *.java
6.
7. 2)create stub and skeleton object by rmic tool
8.
9. rmic AdderRemote
10.
11. 3)start rmi registry in one command prompt
12.
13. rmiregistry 5000
14.
15. 4)start the server in another command prompt
16.
17. java MyServer
18.
19. 5)start the client application in another command prompt
20.
21. java MyClient
Consider a scenario, there are two applications running in different machines. Let's
say MachineA and MachineB, machineA is located in United States and MachineB in
India. MachineB want to get list of all the customers of MachineA application.
First of all, we need to create the table in the database. Here, we are using Oracle10
database.
File: Customer.java
1. package com.javatpoint;
2. public class Customer implements java.io.Serializable{
3. private int acc_no;
4. private String firstname,lastname,email;
5. private float amount;
6. //getters and setters
7. }
File: Bank.java
1. package com.javatpoint;
2. import java.rmi.*;
3. import java.util.*;
4. interface Bank extends Remote{
5. public List<Customer> getCustomers()throws RemoteException;
6. }
File: BankImpl.java
1. package com.javatpoint;
2. import java.rmi.*;
3. import java.rmi.server.*;
4. import java.sql.*;
5. import java.util.*;
6. class BankImpl extends UnicastRemoteObject implements Bank{
7. BankImpl()throws RemoteException{}
8.
9. public List<Customer> getCustomers(){
10. List<Customer> list=new ArrayList<Customer>();
11. try{
12. Class.forName("oracle.jdbc.driver.OracleDriver");
13. Connection con=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","syste
m","oracle");
14. PreparedStatement ps=con.prepareStatement("select * from customer400");
15. ResultSet rs=ps.executeQuery();
16.
17. while(rs.next()){
18. Customer c=new Customer();
19. c.setAcc_no(rs.getInt(1));
20. c.setFirstname(rs.getString(2));
21. c.setLastname(rs.getString(3));
22. c.setEmail(rs.getString(4));
23. c.setAmount(rs.getFloat(5));
24. list.add(c);
25. }
26.
27. con.close();
28. }catch(Exception e){System.out.println(e);}
29. return list;
30. }//end of getCustomers()
31. }
4) Compile the class rmic tool and start the registry service by
rmiregistry tool
File: MyServer.java
1. package com.javatpoint;
2. import java.rmi.*;
3. public class MyServer{
4. public static void main(String args[])throws Exception{
5. Remote r=new BankImpl();
6. Naming.rebind("rmi://localhost:6666/javatpoint",r);
7. }}
6) Create and run the Client
File: MyClient.java
1. package com.javatpoint;
2. import java.util.*;
3. import java.rmi.*;
4. public class MyClient{
5. public static void main(String args[])throws Exception{
6. Bank b=(Bank)Naming.lookup("rmi://localhost:6666/javatpoint");
7.
8. List<Customer> list=b.getCustomers();
9. for(Customer c:list){
10. System.out.println(c.getAcc_no()+" "+c.getFirstname()+" "+c.getLastname()
11. +" "+c.getEmail()+" "+c.getAmount());
12. }
13.
14. }}
If the RMI compiler is successful, this command generates the stub and skeleton
classes, AccountImpl_Stub and AccountImpl_Skel, in the current directory. The
rmic compiler has additional arguments that let you specify where the generated
classes should be stored, whether to print warnings, etc. For example, if you want the
stub and skeleton classes to reside in the directory /usr/local/classes, you can run
the command using the -d option:
This command generates the stub and skeleton classes in the specified directory.
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.
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 in more detail. As 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 in
Figure 13-2.
Figure 13-2. 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.
Stubs and skeletons are generated from the classes that implement the remote RMI
interfaces that you've exported. The process of generating these stub and skeleton
classes is done either dynamically at runtime (in JDK 1.5 or later JVMs) or by using
the RMI compiler . Whether you use the RMI compiler or use dynamic stub and
skeleton generation, the role of these classes in the RMI runtime are the same. The
stub and skeleton classes act as go-betweens for the client application and the actual
server object, respectively. The client stub class implements the remote interface that
you defined, and its implementations of each remote method package up (marshal) the
method arguments provided by the client and transmit them to the server. The
skeleton class is responsible for receiving the method arguments from the RMI
runtime after they've been transmitted over the network. It unpackages (unmarshals)
the method arguments and makes the corresponding method call on the actual remote
object implementation on the server. Whatever response the method call generates
(return data or an exception), the results are packaged and transmitted back to the
remote client by the skeleton and the RMI runtime working together. The client stub
method (which is still executing at this point) unpackages the results and delivers
them to the client as the result of its remote method call.
As we saw earlier in the chapter, the first step in creating your remote objects is to
define the remote interfaces for the types of objects you need to use in a distributed
object context. This isn't much different from defining the public interfaces in a
nondistributed application, with the following exceptions:
Every object you want to distribute using RMI has to directly or indirectly
extend an interface that extends the java.rmi.Remote interface.
[*]
Note that prior to Java 1.2, the RMI
specification required that every method on a
remote interface had to throw RemoteException
specifically. In Java 1.2 and later, this
restriction was loosened to allow any superclass of
RemoteException. One reason for this change is to
make it easier to define generic interfaces that
support both local and remote objects.
RMI imposes the first requirement to allow it to differentiate quickly between objects
that are enabled for remote distribution and those that aren't. As we've already seen,
during a remote method invocation, the RMI runtime system needs to be able to
determine whether each argument to the remote method is a Remote object or not. The
Remote interface, which is simply a tag interface that marks remote objects, makes it
easy to perform this check.
The second requirement is needed to deal with errors that can happen during a remote
session. When a client makes a method call on a remote object, any number of errors
can occur, preventing the remote method call from completing. These include client-
side errors (e.g., an argument can't be marshaled), errors during the transport of data
between client and server (e.g., the network connection is dropped), and errors on the
server side (e.g., the method throws a local exception that needs to be sent back to the
remote caller). The RemoteException class is used by RMI as a base exception class
for any of the different types of problems that might occur during a remote method
call. Any method you declare in a Remote interface is assumed to be remotely
callable, so every method has to declare that it might throw a RemoteException or
one of its parent interfaces.
In Example 13-1 we saw the Account interface, a remote interface that declares six
remote methods: getName( ), getBalance( ), withdraw( ), deposit( ) and
TRansfer( ). Since we want to use this interface in an RMI setting, we've declared
that the interface extends the Remote interface. In addition, each method has
arguments and return values that are either Remote or Serializable, and each
method is declared as throwing a RemoteException.
With the remote interface defined, the next thing we need to do is write a class that
implements the interface. We saw the implementation of the Account interface, the
AccountImpl class, in Example 13-2. This class has implementations of the six
remote methods defined in the Account interface; it also has a nonremote method,
checkTransfer( ), to verify that a funds transfer between two accounts can be
made. Notice that the checkTransfer( ) method doesn't have to be declared as
throwing a RemoteException, since it isn't a remotely callable method. Only the
methods that participate in the remote method protocol of the RMI runtime need to
declare that they can throw RemoteException or one of its parent exceptions. The
methods in your implementation class that participate in the RMI runtime include
implementations of any methods declared in the remote interface (withdraw( ),
transfer( ), etc. in our example) and, if you're extending UnicastRemoteObject,
any constructors on your implementation class. Any other methods you define in your
implementation class (like checkTransfer( )) are considered nonremote (i.e., they
are callable only from within the local Java virtual machine where the object exists).
As you have probably noticed, our AccountImpl class also extends the
UnicastRemoteObject class. This is a class in the java.rmi.server package that
extends java.rmi.server.RemoteServer, which itself extends
java.rmi.server.RemoteObject, the base class for all RMI remote objects. Four
key classes are related to writing server object implementations:
RemoteObject
RemoteServer
UnicastRemoteObject
7.1 Overview
Object activation is a mechanism for providing persistent references to objects and
managing the execution of object implementations. In RMI, activation allows objects
to begin execution on an as-needed basis. When an activatable remote object is
accessed (via a method invocation) if that remote object is not currently executing, the
system initiates the object's execution inside an appropriate JVM.
7.1.1 Terminology
An active object is a remote object that is instantiated and exported in a JVM on some
system. A passive object is one that is not yet instantiated (or exported) in a JVM, but
which can be brought into an active state. Transforming a passive object into an active
object is a process known as activation. Activation requires that an object be
associated with a JVM, which may entail loading the class for that object into a JVM
and the object restoring its persistent state (if any).
In the RMI system, we use lazy activation. Lazy activation defers activating an object
until a client's first use (i.e., the first method invocation).
An activation group (one per JVM) is the entity which receives a request to activate
an object in the JVM and returns the activated object back to the activator.
If the activation group in which this object should reside exists, the activator forwards
the activation request to that group. If the activation group does not exist, the activator
initiates a JVM executing an activation group and then forwards the activation request
to that group.
The activation group loads the class for the object and instantiates the object using a
special constructor that takes several arguments, including the activation descriptor
registered previously.
When the object is finished activating, the activation group passes back a marshalled
object reference to the activator that then records the activation identifier and active
reference pairing and returns the active (live) reference to the faulting reference. The
faulting reference (inside the stub) then forwards method invocations via the live
reference directly to the remote object.
Note: In Java 2 SDK, Standard Edition, v 1.2, RMI provides an implementation of the
activation system interfaces. In order to use activation, you must first run the
activation system daemon rmid.
For a specific object, only one of the above methods should be used to register the
object for activation. See the section below on "Constructing an Activatable Remote
Object" for examples on how to implement activatable objects.
A descriptor registered with the activation system is consulted (during the activation
process) to obtain information in order to re-create or activate an object. The
MarshalledObject in the object's descriptor is passed as the second argument to the
remote object's constructor for the object to use during activation.
package java.rmi.activation;
public final class ActivationDesc implements java.io.Serializable
{
The activation protocol makes use of activation identifiers to denote remote objects
that can be activated over time. An activation identifier (an instance of the class
ActivationID) contains several pieces of information needed for activating an
object:
An activation identifier for an object can be obtained by registering an object with the
activation system. Registration is accomplished in a few ways (also noted above):
package java.rmi.activation;
public class ActivationID implements java.io.Serializable
{
public ActivationID(Activator activator);
The Activatable class provides support for remote objects that require persistent
access over time and that can be activated by the system. The class Activatable is
the main API that developers need to use to implement and manage activatable
objects. Note that you must first run the activation system daemon, rmid, before
objects can be registered and/or activated.
package java.rmi.activation;
public abstract class Activatable
extends java.rmi.server.RemoteServer
{
protected Activatable(String codebase,
java.rmi.MarshalledObject data,
boolean restart,
int port)
throws ActivationException, java.rmi.RemoteException;
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws ActivationException, java.rmi.RemoteException;
To register an activatable remote object with the activation system without first
creating the object, the programmer can simply register an activation descriptor (an
instance of the class ActivationDesc) for the object. An activation descriptor
contains all the necessary information so that the activation system can activate the
object when needed. An activation descriptor for an instance of the class
examples.ServerImpl can be registered in the following manner (exception
handling elided):
Server server;
ActivationDesc desc;
String codebase = "http://zaphod/codebase/";
The register call returns a Remote stub that is the stub for the
examples.ServerImpl object and implements the same set of remote interfaces that
examples.ServerImpl implements (i.e, the stub implements the remote interface
Server). This stub object (above, cast and assigned to server) can be passed as a
parameter in any method call expecting an object that implements the
examples.Server remote interface.
like all system daemons, the activator should remain running while the machine is up, and
the activator must not reactivate remote objects that are already active.
The activator maintains a database of appropriate information for the groups and
objects that it participates in activating.
7.4.1 The Activator Interface
The activator is one of the entities that participates during the activation process. As
described earlier, a faulting reference (inside a stub) calls the activator's activate
method to obtain a "live" reference to an activatable remote object. Upon receiving a
request for activation, the activator looks up the activation descriptor for the
activation identifier, id, determines the group in which the object should be activated,
and invokes the newInstance method on the activation group's instantiator (the
remote interface ActivationGroup is described below). The activator initiates the
execution of activation groups as necessary. For example, if an activation group for a
specific group descriptor is not already executing, the activator will spawn a child
JVM for the activation group to establish the group in the new JVM.
The activator is responsible for monitoring and detecting when activation groups fail
so that it can remove stale remote references from its internal tables.
package java.rmi.activation;
public interface Activator extends java.rmi.Remote
{
java.rmi.MarshalledObject activate(ActivationID id,
boolean force)
throws UnknownObjectException, ActivationException,
java.rmi.RemoteException;
}
package java.rmi.activation;
public interface ActivationSystem extends java.rmi.Remote
{
public static final int SYSTEM_PORT = 1098;
package java.rmi.activation;
public interface ActivationMonitor
extends java.rmi.Remote
{
An activation group calls its monitor's inactiveObject method when an object in its
group becomes inactive (deactivates). An activation group discovers that an object
(that it participated in activating) in its JVM is no longer active via a call to the
activation group's inactiveObject method.
package java.rmi.activation;
public interface ActivationInstantiator
extends java.rmi.Remote
{
public MarshalledObject newInstance(ActivationID id,
ActivationDesc desc)
throws ActivationException, java.rmi.RemoteException;
determining the class for the object using the descriptor's getClassName method,
loading the class from the codebase path obtained from the descriptor (using the
getLocation method),
creating an instance of the class by invoking the special "activation" constructor of the
object's class that takes two arguments: the object's ActivationID, and the
MarshalledObject containing object-specific initialization data, and
returning a MarshalledObject containing the remote object it created.
An instantiator is also responsible for reporting when objects it creates or activates are
no longer active, so that it can make the appropriate inactiveObject call to its
ActivationMonitor (see the ActivationGroup class for more details).
the group's class name (a class name of null indicates the default ActivationGroup
implementation),
the group's codebase path (the location of the group's class), and
a "marshalled" object that can contain object-specific initialization data.
package java.rmi.activation;
public final class ActivationGroupDesc
implements java.io.Serializable
{
The first constructor creates a group descriptor that uses system default for group
implementation and code location. Properties specify Java application environment
overrides (which will override system properties in the group implementation's JVM).
The command environment can control the exact command/options used in starting
the child JVM, or can be null to accept rmid's default. This constructor will create an
ActivationGroupDesc with a null group class name, which indicates the system's
default ActivationGroup implementation.
The second constructor is the same as the first, but allows the specification of
Properties and CommandEnvironment.
The getClassName method returns the group's class name (possibly null). A null
group class name indicates the system's default ActivationGroup implementation.
The getLocation method returns the codebase path from where the group's class can
be loaded.
The getData method returns the group's initialization data in marshalled form.
The equals implements content equality for command environment objects. The
hashCode method is implemented appropriately so that a CommandEnvironment can
be stored in a hash table if necessary.
package java.rmi.activation;
public class ActivationGroupID implements java.io.Serializable
{
public ActivationGroupID(ActivationSystem system);
The getSystem method returns the activation system for the group.
The hashCode method returns a hashcode for the group's identifier. Two group
identifiers that refer to the same remote group will have the same hash code.
The equals method compares two group identifiers for content equality. The method
returns true if both of the following conditions are true: 1) the unique identifiers are
equivalent (by content), and 2) the activation system specified in each refers to the
same remote object.
When created, the default implementation of ActivationGroup will set the system
properties to the system properties in force when the ActivationGroupDesc was
created, and will set the security manager to the java.rmi.RMISecurityManager. If
your application requires some specific properties to be set when objects are activated
in the group, the application should set the properties before creating any
ActivationDescs (before the default ActivationGroupDesc is created).
package java.rmi.activation;
public abstract class ActivationGroup
extends UnicastRemoteObject
implements ActivationInstantiator
{
protected ActivationGroup(ActivationGroupID groupID)
throws java.rmi.RemoteException;
determining the class for the object using the descriptor's getClassName method,
loading the class from the URL path obtained from the descriptor (using the getLocation
method),
creating an instance of the class by invoking the special constructor of the object's class that
takes two arguments: the object's ActivationID, and a MarshalledObject
containing the object's initialization data, and
returning a serialized version of the remote object it just created to the activator.
The method throws ActivationException if the instance for the given descriptor
could not be created.
When an object is placed inside the MarshalledObject wrapper, the serialized form
of the object is annotated with the codebase URL (where the class can be loaded);
likewise, when the contained object is retrieved from its MarshalledObject wrapper,
if the code for the object is not available locally, the URL (annotated during
serialization) is used to locate and load the bytecodes for the object's class.
package java.rmi;
public final class MarshalledObject implements java.io.Serializable
{
public MarshalledObject(Object obj)
throws java.io.IOException;
each class in the stream is annotated with its codebase URL so that when the object is
reconstructed (by a call to the get method), the bytecodes for each class can be located and
loaded, and
remote objects are replaced with their proxy stubs.
For serializing the object, we call the writeObject() method ObjectOutputStream, and
for deserialization we call the readObject() method of ObjectInputStream class.
We must have to implement the Serializable interface for serializing the object.
java.io.Serializable interface
Serializable is a marker interface (has no data member and method). It is used to
"mark" Java classes so that the objects of these classes may get a certain capability.
The Cloneable and Remote are also marker interfaces.
The String class and all the wrapper classes implement the java.io.Serializable
interface by default.
1. import java.io.Serializable;
2. public class Student implements Serializable{
3. int id;
4. String name;
5. public Student(int id, String name) {
6. this.id = id;
7. this.name = name;
8. }
9. }
In the above example, Student class implements Serializable interface. Now its objects
can be converted into stream.
ObjectOutputStream class
The ObjectOutputStream class is used to write primitive data types, and Java objects
to an OutputStream. Only objects that support the java.io.Serializable interface can be
written to streams.
Constructor
Method Description
1) public final void
writes the specified object to
writeObject(Object obj) throws
the ObjectOutputStream.
IOException {}
2) public void flush() throws flushes the current output
IOException {} stream.
3) public void close() throws closes the current output
IOException {} stream.
ObjectInputStream class
Method Description
1) public final Object readObject() throws reads an object from the
IOException, ClassNotFoundException{} input stream.
2) public void close() throws IOException
closes ObjectInputStream.
{}
1. import java.io.*;
2. class Persist{
3. public static void main(String args[]){
4. try{
5. //Creating the object
6. Student s1 =new Student(211,"ravi");
7. //Creating stream and writing the object
8. FileOutputStream fout=new FileOutputStream("f.txt");
9. ObjectOutputStream out=new ObjectOutputStream(fout);
10. out.writeObject(s1);
11. out.flush();
12. //closing the stream
13. out.close();
14. System.out.println("success");
15. }catch(Exception e){System.out.println(e);}
16. }
17. }
success
download this example of serialization
Deserialization is the process of reconstructing the object from the serialized state. It is
the reverse operation of serialization. Let's see an example where we are reading the
data from a deserialized object.
1. import java.io.*;
2. class Depersist{
3. public static void main(String args[]){
4. try{
5. //Creating stream to read the object
6. ObjectInputStream in=new ObjectInputStream(new FileInputStream("f.txt"));
7. Student s=(Student)in.readObject();
8. //printing the data of the serialized object
9. System.out.println(s.id+" "+s.name);
10. //closing the stream
11. in.close();
12. }catch(Exception e){System.out.println(e);}
13. }
14. }
211 ravi
download this example of deserialization
1. import java.io.Serializable;
2. class Person implements Serializable{
3. int id;
4. String name;
5. Person(int id, String name) {
6. this.id = id;
7. this.name = name;
8. }
9. }
1. class Student extends Person{
2. String course;
3. int fee;
4. public Student(int id, String name, String course, int fee) {
5. super(id,name);
6. this.course=course;
7. this.fee=fee;
8. }
9. }
Now you can serialize the Student class object that extends the Person class which is
Serializable. Parent class properties are inherited to subclasses so if parent class is
Serializable, subclass would also be.
1. class Address{
2. String addressLine,city,state;
3. public Address(String addressLine, String city, String state) {
4. this.addressLine=addressLine;
5. this.city=city;
6. this.state=state;
7. }
8. }
1. import java.io.Serializable;
2. public class Student implements Serializable{
3. int id;
4. String name;
5. Address address;//HAS-A
6. public Student(int id, String name) {
7. this.id = id;
8. this.name = name;
9. }
10. }
Since Address is not Serializable, you can not serialize the instance of Student class.
1. class Employee implements Serializable{
2. int id;
3. String name;
4. static String company="SSS IT Pvt Ltd";//it won't be serialized
5. public Student(int id, String name) {
6. this.id = id;
7. this.name = name;
8. }
9. }
Externalizable in java
The Externalizable interface provides the facility of writing the state of an object into a
byte stream in compress format. It is not a marker interface.
1. class Employee implements Serializable{
2. transient int id;
3. String name;
4. public Student(int id, String name) {
5. this.id = id;
6. this.name = name;
7. }
8. }
Now, id will not be serialized, so when you deserialize the object after serialization,
you will not get the value of id. It will return default value always. In such case, it will
return 0 because the data type of id is an integer.
SerialVersionUID
The serialization process at runtime associates an id with each Serializable class which
is known as SerialVersionUID. It is used to verify the sender and receiver of the
serialized object. The sender and receiver must be the same. To verify it,
SerialVersionUID is used. The sender and receiver must have the same
SerialVersionUID, otherwise, InvalidClassException will be thrown when you
deserialize the object. We can also declare our own SerialVersionUID in the
Serializable class. To do so, you need to create a field SerialVersionUID and assign a
value to it. It must be of the long type with static and final. It is suggested to explicitly
declare the serialVersionUID field in the class and have it private also. For example:
1. private static final long serialVersionUID=1L;
1. import java.io.Serializable;
2. class Employee implements Serializable{
3. private static final long serialVersionUID=1L;
4. int id;
5. String name;
6. public Student(int id, String name) {
7. this.id = id;
8. this.name = name;
9. }
10. }
2.7 The JavaSpaces Technology Application Model
There are two look-up operations: read() and take(). The read() method returns
either an entry that matches the template or an indication that no match was found.
The take() method operates like read(), but if a match is found, the entry is
removed from the space. Distributed events can be used by requesting a JavaSpaces
service to notify you when an entry that matches the specified template is written into
the space. Note that each entry in the space can be taken at most once, but two or
more entries may have the exact same values.
As you can see, a client can interact with as many JavaSpaces services as needed.
Clients perform operations that map entries to templates onto JavaSpaces services.
Such operations can be singleton or contained in a transaction so that all or none of
the operations take place. Notifications go to event catches, which can be either
clients or proxies for clients.
You can implement such a multiuser chat system in RMI by creating remote
interfaces for the interactions discussed. But by using JavaSpaces technology, you
need only one interface.