Using Jini from .NET
Introduction
Jini 2.0 delivers everything that Web Services promise, except for language independence. Jini represents an extremely powerful service oriented architecture, with deployment-customizable security and portable, mobile code. You can quickly and inexpensively build resilient, reliable, distributed applications on the basis of the Jini technology starter kit... as long as you are programming in Java.
Unfortunately, many of the enterprises that should be using Jini aren't. One reason is the persistent misperception of Jini as a technology for hardware devices, but another reason is the fact that that Jini is so strongly associated with Java and does not have an easy gateway to other languages and development platforms.
Your problem is that you have started looking at Jini and decided that it has everything that you are looking for in an SOA, but you need to use the SOA from a .NET application on a Windows™ desktop. What do you do?
Solution
What if you could use Jini with all its benefits under the hood while publishing a .NET API to the users of your service? Imagine the Jini out-of-the-box benefits of:
- customizable security (Kerberos, SSL, etc.)
- application resilience in the face of catastrophic device failures
- linear scalability over a wide range
- dynamically deployed smart service proxies
combined with a native .NET API and usability from every C#, VB.NET, managed C++ application. This can be done by exposing Jini and your service interfaces to .NET using JuggerNET.
The following application represents the .NET port of the hello example in the Jini technology starter kit. This .NET application was created the night before the 7th Jini Community Meeting to demonstrate the ease of integration. Most of the four hours it took to port the example was spent on figuring out codebase security (a traditional RMI issue) and had nothing to do with the application port per se. You might not be a Jini specialist, but if you have spent any time at all looking at Jini 2.0 examples, you will see how similar this example is to the underlying Java example.
using System;
using System.Collections;
using System.Configuration;
using Codemesh.JuggerNET;
using com.sun.jini.example.hello;
using java.lang;
using java.security;
using javax.security.auth;
using javax.security.auth.login;
using net.jini.config;
using net.jini.core.lookup;
using net.jini.discovery;
using net.jini.lookup;
using net.jini.security;
namespace hello
{
public class Application
{
//
// A class that is used instead of an anonymous inner class
// to provide optional application security.
//
internal class PrivilegedMain : PrivilegedExceptionAction
{
private net.jini.config.Configuration config = null;
public PrivilegedMain( net.jini.config.Configuration config )
{
this.config = config;
}
public object run()
{
mainAsSubject( config );
return null;
}
};
//
// The application's entry point.
// Here we perform mostly setup and utility functionality before delegating to
// the mainAsSubject() method which does all the real work.
//
public static void Main( string[] args )
{
//use the .NET configuration API to figure out whether we want
//to run with or without SSL
IDictionary settings = (IDictionary)ConfigurationSettings.GetConfig( "Codemesh/JuggerNET/Loader" );
string loader = (string)settings[ "name" ];
bool bUseSSL = loader.Equals( "SSL" );
//for debugging sessions (where we have a harder time with different
//commandline options), we specify the default value
if( args.Length == 0 )
{
if( bUseSSL )
args = new String[] { @"config\ssl-client.config" };
else
args = new String[] { @"config\client.config" };
}
try
{
net.jini.config.Configuration config = ConfigurationProvider.getInstance( args );
//retrieve the authentication requirements from the configuration
LoginContext loginContext = (LoginContext)config.getEntry(
"com.sun.jini.example.hello.Client",
"loginContext",
Class.forName( "javax.security.auth.login.LoginContext" ),
null );
//run without authentication if no loginContext was specified
if( loginContext == null )
mainAsSubject( config );
//otherwise perform the login operation and execute the application
//in the context of the authenticated user. Notice that this
//requires a callback into the run() method of PrivilegedMain.
else
{
loginContext.login();
Subject.doAsPrivileged( loginContext.getSubject(), new PrivilegedMain( config ), null );
}
}
catch( System.Exception e )
{
Console.WriteLine( e.Message );
Console.WriteLine( e.StackTrace );
}
}
//
// The method where all the real work of the hello application is done.
//
public static void mainAsSubject( net.jini.config.Configuration config )
{
//use the SDM to locate our service via its interface
ServiceDiscoveryManager serviceDiscovery = null;
try
{
serviceDiscovery = (ServiceDiscoveryManager)config.getEntry(
"com.sun.jini.example.hello.Client",
"serviceDiscovery",
Class.forName( "net.jini.lookup.ServiceDiscoveryManager" ) );
}
catch( NoSuchEntryException )
{
serviceDiscovery = new ServiceDiscoveryManager(
new LookupDiscovery(
new String[] { "" },
config ),
null,
config );
}
ServiceItem serviceItem = serviceDiscovery.lookup(
new ServiceTemplate(
null,
new Class[] { Class.forName( "com.sun.jini.example.hello.Hello" ) },
null ),
null,
Long.MAX_VALUE );
//extract the service proxy and cast it to the proper type
Hello server = HelloImpl.From( serviceItem.service );
//prepare the proxy for use
ProxyPreparer preparer = (ProxyPreparer)config.getEntry(
"com.sun.jini.example.hello.Client",
"preparer",
Class.forName( "net.jini.security.ProxyPreparer" ),
new BasicProxyPreparer() );
server = HelloImpl.From( preparer.prepareProxy( server ) );
//use the proxy to call the service
Console.WriteLine( "Server says: {0}", server.sayHello() );
}
}
}
Deployment
Your .NET application will require the Codemesh runtime library to be present and it will require a Java Runtime Environment (JRE). You can bundle a so-called "private" JRE with your application, or you can rely on the presence of a JRE on the client host. The latter alternative might be perfectly acceptable in well-controlled intranet deployment scenarios.
Summary
A JuggerNET-based Jini solution combines the strengths of Jini and Codemesh's in-process technology. It leverages JuggerNET in in-process mode to call from .NET into Java and it uses Jini's code mobility, security, etc. for everything else.
