Visual Basic Accessing Java Using Zero Client Installation

Java/J2EE COM Interoperability Products Page

Zero client installation is a form of late binding that does not require any installation on client machines. It provides the ability to access Java objects running anywhere from COM clients running on unmodified Windows machines.

In this article I will show you how you can access Java objects (including EJBs) running on any Operating System from COM clients running on a standard Microsoft Windows NT (SP4 or greater) or Windows 2000 machine. There is zero deployment overhead: you will not have to install any software at all on the Windows client machine.

The example uses Visual BASIC as the COM client, although the same code could be used from environments such as Active Server Pages. On the Java side it uses the J-Integra® pure Java-COM bridge from Intrinsyc. You will need the jintegra.jar file from the kit on the machine running the Java objects that are accessed from COM. Since this is a pure Java jar file, this machine can be running any operating system using any JVM.

To use this zero-client-installation architecture on clients running Windows 10 feature release 1809 or later, a workaround is required. The workaround is described here, and the instructions below will need to be adjusted accordingly.

How does it work?

You use a J-Integra® tool (GetJvmMoniker) to generate a COM objref moniker. This is a long string which represents a reference to a COM object. You can use this string from COM clients to dynamically access a COM object.

In our case the objref moniker string generated by GetJvmMoniker references a JVM Java object (an instance of a J-Integra® built-in Java class) sitting in a JVM running somewhere. This JVM object can be used to instantiate and access instances of other Java classes in the JVM.

Steps

The following steps are involved:

  1. Display the JVM's moniker
  2. Start the JVM
  3. Access Java objects fron the Windows VB client by using the moniker

Display the JVM's moniker

On any machine that has the jintegra.jar file from the J-Integra® kit on it, set your CLASSPATH to include jintegra.jar.

Then run the com.linar.jintegra.GetJvmMoniker Java class, specifying the IP address or full DNS name of the machine running the JVM in which Java objects will be accessed, and a free TCP/IP port number as parameters:

1. Displays protocol statistics and current TCP/IP network connections to make sure whether the port number is free and not used by any other applications:

netstat -a

2. Generate the moniker:

java com.linar.jintegra.GetJvmMoniker mymachine.mycompany.com 1350

Note: If you run the COM client and it crashes with Automation error: The object exporter specified was not found, then you must run the GetJvmMoniker command with the IP address of the machine hosting the JVM (and not the full DNS name).

Note: When generating a moniker for Windows 10 1809 or later, omit the port from the GetJvmMoniker command line and use the workaround described here.

You will see a long message displayed which shows the objref moniker and explains how to use it. The full text is also copied to your clipboard:

If you run the com.linar.jintegra.GetJvmMoniker class on a system which doesn't support GUI (for example, a UNIX system on which XWindows is not configured), use the JINTEGRA_NOCLIPBOARD property:

java -DJINTEGRA_NOCLIPBOARD com.linar.jintegra.GetJvmMoniker localhost 1350

If you do not use this property on a non-GUI system, it will result in a crash when trying to copy the text to clipboard.

Start the JVM

Create a file called TestJvm.java with the following contents:
import com.linar.jintegra.Jvm;

public class TestJvm {
  public static void main(java.lang.String[] args) throws Exception {
    // com.linar.jintegra.Log.logImmediately(3, "jintegra.log");
    Jvm.register("ajvm");
    while (true) {
      // So that the JVM does not terminate immediately
      Thread.sleep(10000);
    }
  }
}

Compile the file using javac TestJvm.java then run it using java -DJINTEGRA_DCOM_PORT=1350 TestJvm

Create the Windows VB client

On the Windows client machine, start Visual BASIC and create a new project of type "Standard EXE".

Double-click on the form that is displayed to edit the code that is run when the form is first displayed when you run the program.

Enter this code to start with, replacing "objref:...:" with the actual text displayed when you started the JVM above:

Private Sub Form_Load()
Set jvm = GetObject("objref:...:")
Set vector = jvm.get("java.util.Vector")
vector.addElement "hello"
vector.addElement "goodbye"
MsgBox vector

For Each elt In vector
    MsgBox elt
Next

End Sub

When you run your VB code you should see three popups, the first being the result of doing Vector.toString() and then the two elements in the vector:

You can use the call to jvm.get("java.util.Vector") to get hold of instances of any public class which has a public default constructor, and you can invoke all public methods and access all public fields, including static ones.

Accessing EJBs

You probably have a few questions at this point, such as What was the point of doing the Jvm.register("aJvm") in the Java code? The answer is that it was really only there to initialise the J-Integra® runtime, however it can also be used to intercept the instantiation request from the COM client, and to return objects that you manufacture:

import javax.naming.*;
import java.util.Hashtable;

import com.linar.jintegra.*;

public class TestJvm {
  public static void main(java.lang.String[] args) throws Exception {
    com.linar.jintegra.Log.logImmediately(3, "jintegra.log");

    Jvm.register("ajvm", new MyInstanciator());
    while (true) {
      // So that the JVM does not terminate immediately
      Thread.sleep(10000);
    }
  }
}

class MyInstanciator implements Instanciator {
  Context ctx;

  MyInstanciator() throws NamingException {
    Hashtable env = new Hashtable(11);
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, "ldap://... TBS ...");
    ctx = new InitialContext(env);
  }

  public Object instanciate(String javaClass) throws AutomationException {
    try {
      // First try to instantiate it as a normal Java class
      try {
        return Class.forName(javaClass).newInstance();
      } catch (Throwable t) {
      }
      // If that fails to a JNDI lookup
      return ctx.lookup(javaClass);
    } catch (Throwable t) {
      t.printStackTrace();
      throw new AutomationException(t);
    }
  }
}

Then in your VB code you can use:

Set anObect = jvm.get("aJvm:cn=ObjectName");

This will cause your instanciation code to be invoked in order to return the object. You can do anything you want in there to instantiate the object.

Once you have access to an Java object from COM you can also access it using early binding (vtable access). Simply add a reference the appropriate type library (either an existing one, or one generated through J-Integra®'s java2com tool), and then access the Java object through the appropriate type in the type library. More explanation will follow in the next release of J-Integra®, however if you walk through some of the step-by-step early-binding examples in the J-Integra® documentation, this should be fairly easy to work out.

Troubleshooting

If you get this "Out of memory" error below, make sure that you have correctly generated the objref moniker, and the Java classes accessed from VB exist.