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.


Copyright 2006-2011 by Codemesh, Inc., ALL RIGHTS RESERVED

:
jini.net
home products support customers partners newsroom about us contact us