RMI


RMI is a mechanism through which we can call remote methods as though they were residing on your own machine. This whole process will look transparent to the end user: if I showed you a live demo and didn't tell you it was RMI, then you wouldn't have even realized the method is actually being called from a different machine. Of course, a Java Virtual Machine must be present on both the machines.

Objects which have to be made available to other machines have to be exported to something called a Remote Registry Server so that they can be invoked. So if Machine A wants to call methods of some object on Machine B, then Machine B would have to export that object on its Remote Registry Server. Remote Registry Server is a service that runs on the server and helps client’s search and access objects on the server remotely. Now, if an object has to be capable of being exported then it must implement the Remote Interface present in the RMI package. For example, say that you want an object Xyz on machine A to be available for remote method invocation, then it must implement the Remote interface.

RMI uses something called a stub and a skeleton. The stub is present on the client side, and the skeleton the server side. When you call remote methods, you don't just go directly to other machine and say "hey, here's the method name, here are the parameters, just give me back what has to be returned and I am out of here".

There are a number of events that have to take place beforehand which help in the communication of the data. The stub is like a local object on the client side, which acts like a proxy of the object on the server side. It provides the methods to the client which can be invoked on the server. The Stub then sends the method call to the Skeleton, which is present on the server side. The Skeleton then implements the method on the server side.

The Stub and the Skeleton communicate with each other through something called a Remote Reference Layer. This layer gives the stub and skeleton the capability to send data using the TCP/IP protocol. Let's take a quick look at a simple technique called "Binding".

Whenever a client wants to make a reference to any object on the server, have you thought how he would tell the server what object he wants to create? Well, this is where this concept of "Binding" comes in. On the server end we associate a string variable with an object (we have methods to do this. We will learn more about these when we start coding). The client tells the server what object he wants to create by passing that string to the server, thus letting the server know exactly what object you are talking about. All of these strings and objects are stored in the Remote Registry Server on the server.

Make your project structure as shown in the image...

Notify.java

// This is the interface that client impliments which - // - gives client ability to hear from server.

package com.client;

import java.rmi.*;

public interface Notify extends Remote{
void notification(String x) throws RemoteException;
}

RmiClient.java
// This is actual client code..!
package com.client;

import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.UnicastRemoteObject;
import java.net.*;

import com.server.*;

public class RmiClient extends UnicastRemoteObject implements Notify{
String address;
Registry myregistry;

public void notification(String x) throws RemoteException{
System.out.println(x);
}
public RmiClient() throws RemoteException{
try{
address = (InetAddress.getLocalHost()).toString();
}
catch(Exception e){
System.out.println("can't get inet address.");
}
int port=4242;
System.out.println("this client address=" + address + ",port=" + port);
try{
myregistry = LocateRegistry.createRegistry(port);
myregistry.rebind("rmiClient", this);
}
catch(RemoteException e){
System.out.println("remote exception"+ e);
}
}
static public void main(String args[]) {
ChatServerInterface rmiServer;
Registry registry;
String serverAddress="localhost";
String serverPort="3232";
String text="hello server, do u wann say some thing to me?";
System.out.println("sending " + text + " to " +serverAddress + ":" + serverPort);
try{
RmiClient client = new RmiClient();
registry=LocateRegistry.getRegistry(serverAddress,(new Integer(serverPort)).intValue());
rmiServer=(ChatServerInterface)(registry.lookup("rmiServer"));
// call the remote method
rmiServer.receiveMessage(text);
}
catch(RemoteException e){
e.printStackTrace();
}
catch(NotBoundException e){
System.err.println(e);
}
catch (Exception e){
e.printStackTrace();
System.exit(1);
}
}
}

ChatServerInterface.java
// this is sever's interface which give ability to hear from client.

package com.server;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ChatServerInterface extends Remote{
void receiveMessage(String x) throws RemoteException;
String receiveMessages(String x, String y) throws RemoteException;
}

RmiServer.java
//Actual server code comes here

package com.server;

import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
import java.net.*;
import com.client.*;


public class RmiServer extends UnicastRemoteObject implements ChatServerInterface{
/* ----------------------------Declaration Part----------------------------*/
private static final int PORT = 3232;
Registry Server_registry;

/* ----------------------------Constructor----------------------------*/
public RmiServer() throws RemoteException
{
try{
//address = (InetAddress.getLocalHost()).toString();
}
catch(Exception e
){
System.out.println("can't get inet address.");
}
System.out.println(" RMI Server started successfully");
try
{
Server_registry = LocateRegistry.createRegistry(PORT);
Server_registry.rebind("rmiServer", this);
}
catch(RemoteException e)
{
System.out.println("remote exception"+ e);
}
}

/* ---------------------------- Implementing Interface----------------------------*/
public void receiveMessage(String x) throws RemoteException
{
Notify notify;
Registry client_registry;
String clientAddress="localhost";
String clientPort="4242";
String reply="yes, How r u?";
System.out.println(x);
try
{
client_registry=LocateRegistry.getRegistry(clientAddress,(new Integer(clientPort)).intValue());
notify=(Notify)(client_registry.lookup("rmiClient"));
notify.notification(reply);
System.out.println("reply sent");
}
catch(RemoteException e)
{
e.printStackTrace();
}
catch(NotBoundException e)
{
System.err.println(e);
}
}
public String receiveMessages(String x,String y) throws RemoteException
{
System.out.println(x + y);
return(x + y);
}
/* ---------------------------- Main ----------------------------*/
static public void main(String args[])
{
try
{
RmiServer server = new RmiServer();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(1);
}
}
}

Reference: Nivelli Mehata's article on RMI.


One can run .exe files using JavaScript from a webpage...

function invoke()
{
try
{
var wsh = new ActiveXObject('WScript.Shell');
}
catch (err)
{
}
var count = parseInt(document.getElementById("textpad_count").value);
wsh.Run("C:\notepad.exe");
}


This concept can be used very efficiently when one deals with opening lot of .exe files for their work frequently. for example: My friend need to open 10 putty clients to connect to a server and 10 text pads simultaneously. This concept helped me a lot.

I used wsh.Run("C:\putty -ssh host -l username -pw password"); in place of wsh.Run("C:\notepad.exe");

Note: host, username and password should be filled with actual vales.

JavaScript gives you power to access local resources on you machine from a webpage, using Activex Object. Here is a Sample how to do it...

function edit()
{
var myApp = new ActiveXObject("Excel.Application"); //invoking EXCEL application
if (myApp != null)
{
myApp.visible = true; //this makes the application visible to us
myApp.workbooks.open("D:\\pin report\\pin_report.xls"); //creates a new work book
myApp.ActiveSheet.Cells(1,1).Value = "Hello World!"; // writes value to a cell
}
}

Note : myApp.visible can be true or false, if we use false then we cannot see the excel application. but it runs in background. we can still access it. Be careful when you use false. use myApp.Close(); after ur work with out fail.

This concept can also be applied to read, write, create a text file. like this...

function read_line_no()
{
var fso, f1, ts;
var ForReading = 1;
fso = new ActiveXObject("Scripting.FileSystemObject");
f1 = fso.CreateTextFile("c:\line_no.txt", true); // a text file is created here
f1.WriteLine("1443");
f1.WriteBlankLines(1);
f1.Close();
ts = fso.OpenTextFile("c:\line_no.txt", ForReading); //Open a text file for reading
line_no = ts.ReadLine(); //read a line from text file
ts.Close(); //Close the text file
}


In this Zone, I post R&D in Coding, Scripting, ...


1) Improving Web page performance
2) Optimize your CSS
3) Obfuscating e-mail address using CSS
4) CSS that helps to detect ClickJacking
5) Gzipping CSS




.......................................................................................................................




1) Accessing Excel,Word etc using javascript
2) Executing .exe files from Web Page
3) Ajax in JavaScript Vs jQuery





.......................................................................................................................


1) Socket Programming
2)
Rmi
3) Using URLConnection class
4) Creating indexes in Oracle
5) Installing https certificates into keystore
6) Base 64 encoding







It goes on...!





Don't tell me you've never chatted on those instant messengers like yahoo, msn and aol. But its OK if you never understood what goes on behind the scene; after all, thats what we are here for. Lets say you've installed one of those instant messengers on your computer. After you run it and enter your user name and password, the messenger tries to connect to its server (say, the yahoo server). What exactly does this 'connect' mean?

Every computer on a network has an IP address. This address is like your house address, something that identifies your computer uniquely, allowing others to communicate with your computer. I wont go much into IP addresses, but let me just tell you that an IP address looks something like this - 64.104.137.158 - a set of numbers separated with dots. However, some computers with rich owners will also choose to have a domain name in addition to this sick looking number, so that people can easily identify them. A domain name looks far more sane - like www.yahoo.com. There are some special computers on the Internet, whose sole purpose in life is to translate the domain name to IP address and vice versa.

Now, you know that many programs can run on the same computer, don't you? Lets say that, there are some 10 programs running on a certain computer. To add to the confusion, lets say all of them are waiting for other computers to contact them. Imagine it like this - 10 of you share a big office space and a single telephone - and all of you expect calls from your own clients. How will you handle this? Perhaps appoint one person who'll hand over the call to the right person. Possible, but an undeniable menace. This will mean, when one of you take the call, other clients will not be able to reach the rest of you. Besides, its a pain to have a person route the calls to the right people. You must have guessed what I'm heading at - if all those programs running on a single computer proudly ask their clients to contact them on a certain IP address, their clients are not going to be pleased. The idea is... having a separate IP address per program, right? WRONG. Thats out of question. Its like asking for a separate office for each of you. Wont separate phone numbers suffice? Yes. In networking parlance, we call these 'separate phone numbers' as ports. A port is just a simple number - each program running on the same computer can choose to have a unique port number to identify itself to the outside world. REMEMBER - these ports are not slots on your computer hardware - dont think you can find them if you try hard enough. They are just logical numbers. Now the point should be clear. We have an IP address that lets the other computers look for a certain computer on the network. And we have a port number that'll identify a certain program running on that computer. Understand that, two programs running on different computers CAN use the same port number. Two houses on different streets can have the same house number, can't they? So, finally, we are almost there - just to scare you a bit, lets derive a formula -

An IP address = uniquely identifies a computer on the network. A port number = uniquely identifies a program running on a computer.

Adding the above equations,

An IP address + A port number = _______

In other words, A _____ = uniquely identifies a program on the network

If you guessed it right, thanks, my effort didn't go waste. If you didn't, no problem, go back and read from the beginning, or google for a better tutorial. The ____ is... SOCKET!

To summarize, a socket is a combination of an IP address and a port. A socket address lets other computers on the network locate a certain program running on a certain computer. You may represent a socket address like 64.104.137.58:80, where 64.104.137.58 is the IP address and 80 is the port number.


I hope I gave all of u fabulous introduction to world of network programming. Feel free to shoot your questions, I'll answer them if I can. You can also give me your valuable feedback, suggestions, or the mistakes you found in this tutorial.

Below are the codes for Server and client respectively! (I always find easy to create and run java project using Eclipse oy My eclipse).

sever Code:

package muti_user_chat;
import java.net.Socket;
import java.net.ServerSocket;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.HashSet;


/**
* A multithreaded chat room server. When a client connects the
* server requests a screen name by sending the client the
* text "SUBMITNAME", and keeps requesting a name until
* a unique one is received. After a client submits a unique
* name, the server acknowledges with "NAMEACCEPTED". Then
* all messages from that client will be broadcast to all other
* clients that have submitted a unique screen name. The
* broadcast messages are prefixed with "MESSAGE ".
*
* Because this is just a teaching example to illustrate a simple
* chat server, there are a few features that have been left out.
* Two are very useful and belong in production code:
*
* 1. The protocol should be enhanced so that the client can
* send clean disconnect messages to the server.
*
* 2. The server should do some logging.
*/
public class ChatServer {

/**
* The port that the server listens on.
*/
private static final int PORT = 9001;

/**
* The set of all names of clients in the chat room. Maintained
* so that we can check that new clients are not registering name
* already in use.
*/
private static HashSet names = new HashSet();

/**
* The set of all the print writers for all the clients. This
* set is kept so we can easily broadcast messages.
*/
private static HashSet writers = new HashSet();

/**
* The appplication main method, which just listens on a port and
* spawns handler threads.
*/
public static void main(String[] args) throws Exception {
System.out.println("The chat server is running.");
ServerSocket listener = new ServerSocket(PORT);
try {
while (true) {
new Handler(listener.accept()).start();
}
} finally {
listener.close();
}
}

/**
* A handler thread class. Handlers are spawned from the listening
* loop and are responsible for a dealing with a single client
* and broadcasting its messages.
*/
private static class Handler extends Thread {
private String name;
private Socket socket;
private BufferedReader in;
private PrintWriter out;

/**
* Constructs a handler thread, squirreling away the socket.
* All the interesting work is done in the run method.
*/
public Handler(Socket socket) {
this.socket = socket;
}

/**
* Services this thread's client by repeatedly requesting a
* screen name until a unique one has been submitted, then
* acknowledges the name and registers the output stream for
* the client in a global set, then repeatedly gets inputs and
* broadcasts them.
*/
public void run() {
try {

// Create character streams for the socket.
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);

// Request a name from this client. Keep requesting until
// a name is submitted that is not already used. Note that
// checking for the existence of a name and adding the name
// must be done while locking the set of names.
while (true) {
out.println("SUBMITNAME");
name = in.readLine();
if (name == null) {
return;
}
synchronized (names) {
if (!names.contains(name)) {
names.add(name);
break;
}
}
}

// Now that a successful name has been chosen, add the
// socket's print writer to the set of all writers so
// this client can receive broadcast messages.
out.println("NAMEACCEPTED");
writers.add(out);
// Now, send list of users to all the clients using above hashset.
for (PrintWriter writer : writers) {
writer.println("USERS "+ names);
}

// Accept messages from this client and broadcast them.
// Ignore other clients that cannot be broadcasted to.
while (true) {
String input = in.readLine();
System.out.println(input);
if (input == null) {
return;
}
for (PrintWriter writer : writers) {
writer.println("MESSAGE " + name + ": " + input);
}
}
} catch (IOException e) {
System.out.println(e);
} finally {
// This client is going down! Remove its name and its print
// writer from the sets, and close its socket.
if (name != null) {
names.remove(name);
}
if (out != null) {
writers.remove(out);
}
try {
socket.close();
} catch (IOException e) {
}
}
}
}
}

Client Code:

package muti_user_chat;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/**
* A simple Swing-based client for the chat server. Graphically
* it is a frame with a text field for entering messages and a
* textarea to see the whole dialog.
*
* The client follows the Chat Protocol which is as follows.
* When the server sends "SUBMITNAME" the client replies with the
* desired screen name. The server will keep sending "SUBMITNAME"
* requests as long as the client submits screen names that are
* already in use. When the server sends a line beginning
* with "NAMEACCEPTED" the client is now allowed to start
* sending the server arbitrary strings to be broadcast to all
* chatters connected to the server. When the server sends a
* line beginning with "MESSAGE " then all characters following
* this string should be displayed in its message area.
*/
public class ChatClient1 {

BufferedReader in;
PrintWriter out;
String MyName = null;
JFrame frame = new JFrame("Chat Box");
JTextField textField = new JTextField(40);
JTextArea messageArea = new JTextArea(8, 40);
JTextArea ClientsAvailable = new JTextArea(9, 10);
JButton sendButton = new JButton("Send");
JButton SignoutButton = new JButton("Sign Out");
JTextField statusColor = new JTextField(1);
JLabel statusField = new JLabel();

JPanel Pane = new JPanel(new BorderLayout()); //Im main panel.
JPanel DisplayBar = new JPanel(new BorderLayout()); //I hold text areas
JPanel InputBar = new JPanel(new BorderLayout());
//I hold input box and button
JPanel statusBar = new JPanel(new BorderLayout()); //I hold Status details
/**
* Constructs the client by laying out the GUI and registering a
* listener with the textfield so that pressing Return in the
* listener sends the textfield contents to the server. Note
* however that the textfield is initially NOT editable, and
* only becomes editable AFTER the client receives the NAMEACCEPTED
* message from the server.
*/
public ChatClient1() {

// Layout GUI.
// Set some defaults.
textField.setEditable(false);
messageArea.setEditable(false);
ClientsAvailable.setEditable(false);
statusColor.setBackground(Color.red);
statusField.setText("Not Yet Connected");
sendButton.setSize(10,10);
//SignoutButton.setSize(10, 10);
//add respective components to their panels.
DisplayBar.add(new JScrollPane(messageArea), BorderLayout.WEST);
DisplayBar.add(new JScrollPane(ClientsAvailable), BorderLayout.EAST);
InputBar.add(textField, BorderLayout.WEST);
InputBar.add(sendButton, BorderLayout.CENTER);
statusBar.add(statusColor, BorderLayout.WEST);
statusBar.add(statusField, BorderLayout.CENTER);
//statusBar.add(SignoutButton, BorderLayout.EAST);
//add panels to main panel.
Pane.add(DisplayBar, BorderLayout.NORTH);
Pane.add(InputBar,BorderLayout.CENTER);
Pane.add(statusBar, BorderLayout.SOUTH);
//add main panel to frame.
frame.setContentPane(Pane);
//pack the frame for display.
frame.pack();
frame.setLocation(200, 200);

// Add Listeners
textField.addActionListener(new ActionListener() {
/**
* Responds to pressing the enter key in the textfield by sending
* the contents of the text field to the server. Then clear
* the text area in preparation for the next message.
*/
public void actionPerformed(ActionEvent e) {
System.out.println(textField.getText());
out.println(textField.getText());
textField.setText("");
}
});
sendButton.addActionListener(new ActionListener() {
/**
* Responds to clicking the button by sending
* the contents of the text field to the server. Then clear
* the text area in preparation for the next message.
*/
public void actionPerformed(ActionEvent e) {
System.out.println(textField.getText());
out.println(textField.getText());
textField.setText("");
}
});
}

/**
* Prompt for and return the address of the server.
*/
private String getServerAddress() {
return JOptionPane.showInputDialog(
frame,
"Enter IP Address of the Server:",
"Welcome to the Chat Box",
JOptionPane.QUESTION_MESSAGE);
}

/**
* Prompt for and return the desired screen name.
*/
private String getName() {
return JOptionPane.showInputDialog(
frame,
"Choose a screen name:",
"Screen name selection",
JOptionPane.PLAIN_MESSAGE);
}

/**
* Connects to the server then enters the processing loop.
*/
private void run() throws IOException {

// Make connection and initialize streams
String serverAddress = getServerAddress();
Socket socket = new Socket(serverAddress, 9001);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);

// Process all messages from server, according to the protocol.
while (true) {
String line = in.readLine();
if (line.startsWith("SUBMITNAME"))
{
//this takes the input name and sends it to server.
MyName = getName();
out.println(MyName);
} else if (line.startsWith("NAMEACCEPTED"))
{
// this sets input text area edit_able and also changes the status to ready.
textField.setEditable(true);
frame.setTitle(MyName + "'s Chat Box");
statusColor.setBackground(Color.green);
statusField.setText("Hi "+MyName+"..! U R Connected to Server");
} else if (line.startsWith("MESSAGE")) {
//this adds the broad casted message to top left text area.
messageArea.append(line.substring(8) + "\n");
}else if (line.startsWith("USERS"))
{
// This part of the code adds the new user list along with my self to top right text area.
line = line.substring(7);
line = line.replace("]", "");
ClientsAvailable.setText("");
String[] Users = line.split(",");
for (String user : Users)
{
ClientsAvailable.append(user + "\n");
}
}
}
}

/**
* Runs the client as an application with a closeable frame.
*/
public static void main(String[] args) throws Exception {
ChatClient1 client = new ChatClient1();
client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
client.frame.setVisible(true);
client.run();
}
}


References:
  • V Karthik`s explination of socket programming!
  • Loyola Marymount University.