Those of you who already know me as The Remoting Guy won’t be surprised to hear that I was positively excited when I read the first announcement of Intrinsyc’s Ja.NET. This product promises to extend the reach of .NET Remoting to Java by supporting bi-directional communication between Java clients or servers and .NET clients or servers. I really couldn’t wait to get my hands on it to test it in some real-world-like scenarios.
Download and installation were absolutely straightforward. It was more or less a matter of click next, next, next?done. When downloading Ja.NET for evaluation you will receive a 60-day evaluation license which is sent to you by email.
|Author Note: Save the emailed license file to a directory because you will need it later when editing the configuration files.
Because .NET Remoting lets you pass objects by value or by reference, the first thing I wanted to test is whether Ja.NET fully supports both. To do this, I implemented a set of tests in both Java and C# that check for client side and server side interoperability between Java and .NET.
I started out with the following set of Java classes. Listing 1 shows a factory class (MyFactory) that creates CustomerManager objects (see Listing 2), which manage Customer objects (see Listing 3) each of which may contain an Address class (see Listing 4). These four classes are sufficient to test server-side functionality.
Using these classes, you can check the two most important features of .NET Remoting: passing objects by reference, which is implemented as a factory design pattern from within MyFactory, and passing nested object structures by value, implemented by the CustomerManager.GetCustomer() and CustomerManager.StoreCustomer() methods.
After compiling the example you need to take two underdocumented steps.
First, you must generate the .NET proxies that will allow the client to access the remote objects. To do that, switch to a command prompt and start the GenNet proxy generation wizard by running the following command line from the directory where your .class files reside:
java -classpath c:janetlibgennet.jar;. com.intrinsyc.janet.gennet.GenNetApp
Second, wrapper generation does not occur within a Java process; it occurs in a Windows Service installed during the setup of Ja.NET. You must supply the connection information to the service. The manual contains an incorrect URI; the correct URI is tcp://localhost:8001. After adding the classes for which you want to generate proxies, you must select which classes you want to pass by value (as a copy). For the sample above, these will be Address and Customer.
On the next page of the proxy generation wizard, specify the destination assembly name and path for the .NET proxy assembly. Note that you must specify the .DLL extension for the assembly here! In this example, I used the assembly name FirstDotNetProxies.DLL.
GenNet stores your settings in a file so that you can invoke it with a ?nogui parameter. This lets you regenerate the proxies directly from your build environment without going through the wizard each time.
Creating the C# client
After creating the .NET proxy assembly, you need to create a client side application (see Listing 5) to test the process.
This sample first creates a proxy to the remote factory object and acquires a new object reference for a CustomerManager object. It then fetches a populated Customer object, changes it, and passes it back to the server. It’s important to note that the behavior of the new operator in .NET changes after the call to RemotingConfiguration.Configure(). Using new no longer creates a reference to a local object, it creates a so called TransparentProxy object instead. The proxy forwards all calls to the remote object.
To make this sample work, you also have to supply a .NET Remoting configuration file (see Listing 6). The configuration file specifies that whenever you create an instance of the class MyFactory using the new operator from the client side assembly FirstDotNetProxies (no .DLL here!), the framework should instead create a proxy to a remote object, located at http://localhost:3456/MyFactory.rem.
You also have to configure Ja.NET. Intrinsyc supplies a tool named Janetor that lets you create and edit Ja.NET configuration files.
You configure Ja.NET using XML files just as you do with .NET Remoting. The difference is that you shouldn’t modify these files manually?you should use the Janetor tool instead. To start this tool, run the following command line from the directory where your .class files are located:
java -jar c:JaNETlibjanetor.jar
The Janetor is a sophisticated (but underdocumented) tool. To make the sample above run as expected, you must first import the license file I mentioned earlier?the one you receive via email after downloading and installing Ja.NET. You do this by right-clicking on “Licensing” and choosing “Install license ?” after which you’ll have to select the license file from wherever you saved it on disk.
Next, you must register the classes to which you will allow your clients to connect. First, right-click on “Local Objects” and add the class MyFactory.
In the configuration screen for this class you will then have to specify the mode. Ja.NET supports both server-activated objects (SAO) and client-activated objects (CAO). SAOs can be compared to classic Web services. When a client calls a method on the specified objects, they can either be handled by the same instance (Singleton) or by a new object created and destroyed for each request (SingleCall). In contrast, client-activated objects are like “conventional” objects, in that a client creates them on request. The clients hold distinct references that are bound to certain server-side instances.
In this example, publish MyFactory in “Server-singleton” mode. You then have to specify a URL used to send requests to this object. I chose tcp://localhost:3456/MyFactory.rem for this. The last setting?and for a casual user probably the most confusing one?is the “Assembly Name.” Here you have to specify the assembly which will contain the .NET proxies. Note that you must not specify a .DLL extension here. If you’re following the example code, you should set the Assembly Name to “FirstDotNetProxies”.
Another difference between Ja.NET and classic .NET Remoting is that in Remoting, you don’t have to register client-activated objects returned from methods. But with Ja.NET you must do this?otherwise you’ll end up with a somewhat uncooperative NullReferenceException. Therefore the next step is to add the class CustomerManager with the mode “Client”. Use the URI tcp://localhost:3456/CustomerMgr and the same assembly name you used before, (FirstDotNetProxies in the sample code).
Yet another major difference between .NET Remoting and Ja.NET is that in the latter you have to specify information for a “default” class. Here you should set the mode to “Server-singleton”, do not provide an URI, and set the assembly name to “FirstDotNetProxies” again. The reason for this is that Ja.NET uses this assembly name to transfer objects by value. Without it, you won’t be able to pass objects of type Customer or Address from Java to .NET.
able 1 shows the complete list of settings for this application.
Starting the application
If you’re about to use the Ja.NET standalone server (as opposed to hosting it in your favorite EJB container), you can start it with the following command-line:
java -classpath c:janetlibjanet.jar;. com.intrinsyc.janet.Main
Then you can compile and start the C# client which should produce the following output:
Customer: John Doe Street, City: One Microsoft Way, Redmond, WA
On the server console, you should now see the following:
Customer: John Doe No address yet. Customer: John Doe Address: 4150 Network Circle Santa Clara, CA
You’ve seen the basics for using Ja.NET to communicate between a .NET client application and a Java server application. Here’s a brief list of Ja.NET’s other features. First and foremost, you can use both .NET Remoting channels: the HTTPChannel using a SOAP wire format and the TCPChannel with its proprietary, smaller binary format. You manage object lifetime using leases, which you can configure in Janetor for client-activated objects. Different from .NET Remoting, server-side Java singletons are not lifetime managed (in .NET they can timeout as well) and exist for the full lifetime of the application.
All this functionality is available regardless of whether you’re running either Java or .NET on either the client or the server side. Ja.NET is completely bi-directional!
.NET Remoting is a fairly new technology and Ja.NET 1.0 has been only recently released; therefore some of the more advanced features are not yet implemented (most of them are nevertheless officially or unofficially announced for the next release or service pack). For example, in this version it’s impossible to use sponsors with client-activated objects because the lifetime management is based on leases alone. Other things not yet possible are using events and out or in/out parameters. However, Intrinsyc has announced that the next version will support transparent mapping of .NET and Java collection classes.
Read the Manual!
If you want to use or evaluate Ja.NET: read the manual! It’s a very brief but absolutely essential read. Using the Janetor, GenNet, and GenJava tools is not as straightforward and intuitive as one might wish. Sometimes you have to enter relative paths, sometimes absolute paths; sometimes you need to enter the .DLL extension but in other places it must not be present?the user interface doesn’t really help you here.
If mysterious exceptions (like the already mentioned NullReferenceException) begin to occur in an otherwise perfect program, check all the data you recently changed in these tools. It’s quite likely you have inadvertently entered something in a wrong format.
In my opinion, Ja.NET is a great step in the right direction. Opening .NET Remoting to Java seems like a natural thing to do and Intrinsyc did a good job implementing it. When compared to other Web Service toolkits or application servers, the pricing is reasonable: Ja.NET is priced by machine (not by CPU!). The machine license also includes ten licenses for development, testing, and staging. A notable (and unfortunately not yet very common) bonus is that Intrinsyc also officially supports Ja.NET running on the open source JBoss application server. Ja.NET comes with a 60-day evaluation license, which should give you more than enough time to try it with your applications.
The sloppy tool user interfaces and Ja.NET’s not-so-helpful error messages make first-time evaluation a little bit harder but shouldn’t affect your day-to-day work after you get used to them.
Ja.NET is definitely capable of solving some of today’s most daunting tasks in cross platform applications, especially because it supports fast TCP channel and client-activated objects?two things which aren’t available with classic Web Services toolkits. I’m really looking forward to receiving the next version, because the announced features will make Ja.NET a killer application.