Introduction
.NET and J2EE are both widely used technologies for creating Middleware solutions. Sometime we do have code that can get us more benefit from running on the .NET framework and some of the code exists in J2EE application already. And also to achieve the best of everything in short time, we sometime need to migrate our existing code to another environment instead of redesigning and rewriting them. For many customers, migration of technology will happen over time and there is a huge opportunity exists in migration space.
In these two technologies, both .Net Remoting and Java RMI are mechanisms that allow the user to invoke method/methods in another address space. The other address space could be on the same machine or a different one. These two mechanisms can be regarded as RPC in an object-oriented fashion. This article describes how to migrate java RMI applications to .NET Remoting applications, with practical examples.
Before the migration process starts, we can make a comparison of these two concepts as:
Java RMI vs. DotNet Remoting:
Java RMI VS .NET Remoting |
.NET Remoting |
Java RMI |
Proxy |
Dynamics |
Statics (rmic) or dynamics |
Skeletons |
Integrated into Framework |
Integrated into Framework |
Distributed object |
Classes / Remote Interfaces |
Remote Interfaces |
Configuration |
File XML/ System Property |
System Property |
Distributed directory |
No |
RmiRegistry |
Addition of protocols |
Channels |
SocketFactoryImpl |
Addition of formats |
Formatters |
Serialization |
Activation |
Server (SingleCall or Singleton) and Client activated |
API with dimensions waiter Activable objects |
CustomProxy |
Custom RealProxy |
Dynamic Proxy |
Existing protocols |
HTTP, TCP, SOAP |
JRMP, IIOP, ORMI (Orion), T3 in WebLogic |
Management of error |
Remote Exceptions |
Remote Exceptions |
The Migration
Let us start our migration by creating a simple RMI application that will be use in our process of migration to .NET Remoting. This small application will accept a name from client and return a welcome message.
The RMI Solution
Our RMI Solution will comprise of:
- A remote Interface
- A remotable class which implements the interface
- A Server which will sit and listen for object requests
- A Client that will make requests for the remotable object
Now create a folder Called RMISample. We will use this as our default folder for the RMI solution.
The Remote Interface
Create a java file call RemoteInterface.java and paste the following code. It contains two methods that will be implementing by a remotable class.
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteInterface extends Remote
{
public void WriteName(String str) throws RemoteException;
public String ReadWelcome() throws RemoteException;
}
The Implementation
Create a java file call RemoteClass.java and paste the following code. Here we are implementing the remote methods ReadWelcome and WriteName. We will get a name (string) from the ReadWelcome method and will return a welcome message to the client application.
import java.rmi.RemoteException;
public class RemoteClass implements RemoteInterface {
private static String strWelcomeClient;
RemoteClass ()
{
System.out.println("Object created");
}
public String ReadWelcome()
{
return strWelcomeClient;
}
public void WriteName(String strNameFromClient)
{
strWelcomeClient = "HI " + strNameFromClient +
". Welcome to RMI World!!";
}
}
Our remote object class must implement the remote interface (RemoteInterface). And since we doesn’t throw any exception, we can omit the import of RemoteException.
The Server Application
Create a java file call Server.java and paste the following code. In this application, we are creating an instance of the remote object and exporting it. Finally we bind this instance to the RMI registry. Here I am using cincom as the binding name.
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class Server
{
public Server() {}
public static void main(String args[])
{
try
{
RemoteClass robj = new RemoteClass();
RemoteInterface stub = (RemoteInterface)
UnicastRemoteObject.exportObject(robj, 0);
Registry registry = LocateRegistry.getRegistry ();
registry.bind("cincom", stub);
System.out.println("The Server is ready .... Press the
enter key to exit...");
}
catch (Exception e)
{
System.err.println("Server exception thrown: " +
e.toString());
}
}
}
The exportObject() method takes two parameters, the instance of the remote object and the TCP port number. Here we are passing 0 for the default port number of RMI which is 1099.
The Client Application
To call our remote method, we need to create a Client application. Now create a java file call Client.java and paste the following code. Before calling the remote method, we should locate the host from the registry mechanism and then look up the remote object by its name. In our server application, we used cincom as the name of the object. So we are using this name cincom for the lookup again.
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client
{
private static RemoteInterface stub = null;
private Client() {}
public static void main(String[] args)
{
try
{
Registry reg = LocateRegistry.getRegistry("localhost");
// localhost OR your server name
stub = (RemoteInterface) reg.lookup("cincom");
}
catch (Exception e)
{
System.err.println("Client exception thrown: " +
e.toString());
}
String strArgs;
if (args.length == 0)
{
strArgs = "Client";
}
else
{
strArgs = args[0];
}
try
{
stub.WriteName(strArgs);
System.out.println(stub.ReadWelcome());
}
catch(Exception e)
{
System.out.println("Remote method exception thrown: " +
e.getMessage());
}
}
}
Running Application
- open a dos command prompt
- change the current working directory to your RMI directory …/RMISample/
- compile all the java files using java –d . *.java
- Note: If you are using jdk below 1.5.0, you must use rmic utility to generate a stub class using rmic –v1.2 Server
- run the rmiregistry using start rmiregistry
- start the Server using start java Server
- run the Client with a name as argument using Client TestName
You will get an output as
HI TestName. Welcome to RMI World!!
Migrating the application to .NET Remoting
Introduction
The migration can be done in two ways. First, we can do the migration page by page (class by class). And in another (general) technique, we can have a remotable class, a server and a client with configuration files to set up our channels and formatters. Now let us start the migration using the first technique.
First Technique
In this technique, we will do the migration page by page (class by class). Parallel to the RMI application, our .NET Remoting system will comprise of:
- An Interface
- A remotable class which implements the interface
- A Server which will sit and listen for object requests
- A Client that will make requests for the remotable object
The Project
Create a folder Called Remoting.
The Interface
Inside the Remoting folder create a csharp file call RemoteInterface.cs and paste the following code.
public interface RemoteInterface
{
void WriteName(string str);
string ReadWelcome();
}
The Implementation
Inside the Remoting folder create another java file call RemoteClass.cs and paste the following code.
using System;
public class RemoteClass : MarshalByRefObject, RemoteInterface
{
private static string strWelcomeClient;
RemoteClass()
{
Console.WriteLine("Object created");
}
public string ReadWelcome()
{
return strWelcomeClient;
}
public void WriteName(string strNameFromClient)
{
strWelcomeClient = "HI " + strNameFromClient +
". Welcome to Remoting World!!";
}
}
Here we are implementing the methods ReadWelcome and WriteName.
The Server Application
Again inside the Remoting folder create one more java file call RemoteClass.cs and paste the following code. For communication among applications and appDomains, .NET framework includes two default channels:
- HttpChannel (using SOAP formatting)
- TcpChannel (using binary formatting)
Here we are using TcpChannel.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
public class Server
{
public static Main(string [] args)
{
TcpChannel channel = new TcpChannel(8888);
ChannelServices.RegisterChannel(channel);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(RemoteClass), "cincom",
WellKnownObjectMode.SingleCall );
System.Console.WriteLine("The Server is ready .... Press the
enter key to exit...");
System.Console.ReadLine();
}
}
In object activation, Marshal By Value objects have a simple activation scheme, they are crerated when the client first requests them. But Marshal By Reference objects have two activation schemes:
- Server Activated Objects (SAO)
- Client Activated Objects (CAO)
Server activated objects have two registration types, Singleton and SingleCall. Singleton objects are instantiated one time only, and services all client requests in a multi-threaded fashion. SingleCall object are at the other extreme, every time a remote method is invoked on these types of SAO a new remote object is created. In our case we are using SingleCall type.
The Client Application
Now create another folder call Client. Copy the RemoteInterface.cs file and create another file Client.cs inside that folder. Now paste the following code to that new file.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
public class Client
{
public static Main(string [] args)
{
TcpChannel chan = new TcpChannel();
ChannelServices.RegisterChannel(chan);
// Create an instance of the remote object
RemoteInterface obj = (RemoteInterface) Activator.GetObject(
typeof(RemoteInterface), "tcp://localhost:8888/cincom" );
// localhost OR your server name
if( obj.Equals(null) )
{
System.Console.WriteLine("Error: unable to locate server");
}
else
{
String strArgs;
if (args.Length == 0)
{
strArgs = "Client";
}
else
{
strArgs = args[0];
}
obj.WriteName(strArgs);
System.Console.WriteLine(obj.ReadWelcome());
}
}
}
Running Application
- open Visual studio command prompt from Visual studio tools.
- change the Current working directory to your remoting directory …/Remoting/
- compile all the csharp files using csc *.cs
- run the Srver using start Server
- change the current working directory to your client folder …/Client/
- compile all the csharp files using csc *.cs
- run the Client with a name (TestName) as argument using Client TestName
You will get an output as
HI TestName. Welcome to Remoting World!!
Second Technique
This time we will follow the general .NET Remoting technique and we will use configuration files to set up our channels and formatters. This time our .NET Remoting system will comprise of:
- A remotable object (Abstract class and implementation)
- A Sever console application which will sit and listen for object requests
- Configuration file for the Server
- A Client console application that will make requests for the remotable object
- Configuration file for the Client.
The Remotable object
Create a new class library project called and add the following class (RemoteInterface) to the project and compile it. From this process we will get RemoteClass.dll.
using System;
public class RemoteClass : MarshalByRefObject
{
private static string strWelcomeClient;
public RemoteClass()
{
Console.WriteLine("Object created");
}
public string ReadWelcome()
{
return strWelcomeClient;
}
public void WriteName(string strNameFromClient)
{
strWelcomeClient = "HI " + strNameFromClient +
". Welcome to Remoting World!!";
}
}
The Server
Create a console application project called Server. Add a reference to the RemoteClass.dll and add a class (Server) as below.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
public class Server
{
public static Main(string [] args)
{
RemotingConfiguration.Configure("Server.exe.config");
System.Console.WriteLine("The Server is ready .... Press the
enter key to exit...");
System.Console.ReadLine();
}
}
To configure through a configuration file, add an app.config file and add the following lines. As in earlier case, we are using SingleCall activation type.
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
mode="SingleCall"
type="RemoteClass, RemoteClass"
objectUri="RemoteClass.rem"
/>
</service>
<channels>
<channel ref="http" port="8888"/>
</channels>
</application>
</system.runtime.remoting>
</configuration>
The Client Application
Create another console application project called Client. Add a reference to the RemoteClass.dll and add a class (Client) as below.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
public class Client
{
public static Main(string [] args)
{
RemotingConfiguration.Configure("Client.exe.config");
RemoteClass obj = new RemoteClass();
if( obj.Equals(null) )
{
System.Console.WriteLine("Error: unable to locate server");
}
else
{
String strArgs;
if (args.Length == 0)
{
strArgs = "Client";
}
else
{
strArgs = args[0];
}
obj.WriteName(strArgs);
System.Console.WriteLine(obj.ReadWelcome());
System.Console.ReadLine();
}
}
}
Add an app.config file to you project and add the following entries:
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown
type="RemoteClass, RemoteClass"
url="http://localhost:8888/RemoteClass.rem"
/>
</client>
</application>
</system.runtime.remoting>
</configuration>
If you are running in different machine than, instead of localhost, use the name of the computer where the Server application is running.
Running Application
- Run the Server application.
- You will get a message as
The Server is ready .... Press the enter key to exit...
- Run the Client application
You will get an output as
HI Client. Welcome to Remoting World!!