|
|
| |
Programming
WebLogic jCOM uses the Windows Distributed COM (DCOM) network protocol to provide communication between both local and remote COM components and a pure Java environment. The following sections describe what the programmer has to do in order to use WebLogic jCOM to access Java components from a COM client:
Server-Side Programming Requirements
The programming requirements on the server side are, for most programming models, limited to configuration and compiling and activating the bridge. When implementing an early bound programming model or a late bound encapsulation programming model you have to, in addition, generate wrappers and a type library.
The bridge file, JCOMBridge.java, is provided with the WebLogic jCOM installation. This file is used in all the examples provided and can be used as a base for creating your own bridge file, should you wish to do this.
To establish the bridge on the server side, the following needs to be done, irrespective of the programming model being implemented:
env.put(Context.PROVIDER_URL, "t3://localhost:7001")
ant
java -classpath %CLASSPATH% -DJCOM_DCOM_PORT=7050 JCOMBridge
where 7050 is the port where the WebLogic jCOM bridge must listen for client-to-server communications.
The bridge file, JCOMBridge.java, defines the WLS TCP/IP address and listen port and registers the JVM name with JNDI.
If you are implementing early binding or late bound encapsulation, the following additional steps are required:
java com.bea.java2com.Main
When this line is executed, the java2com window will pop up. In the Java Classes & Interfaces field, you must enter the names of the classes you wish to use, including the bridge class.
javac Output Directory\*.java
Client-Side Programming Requirements
For the programing steps required on the client system, we will look at how to implement the following programming models:
DCOM Zero Client Programming Model
The basic client-side programming steps required to implement a DCOM zero client programming model are (described below for a VB client accessing an EJB on the WebLogic Server):
java com.bea.jcom.GetJvmMoniker mymachine.mycompany.com 7050
or
java com.bea.jcom.GetJvmMoniker localhost 7050
Set objBridge = GetObject("objref:generatedobjref")
Set objHome = objBridge.get("JVMName:jndi name of ejb")
DCOM Late Bound Programming Model
The basic client-side programming steps required to implement a DCOM late bound programming model are (described below for a VB client accessing an EJB on the WebLogic Server):
Dim objHome As Object
Private Sub Form_Load()
'Handle errors
On Error GoTo ErrOut
'Bind the EJB's HomeInterface object via JNDI
Set objHome = GetObject("JVMName:jndi name of ejb")
GetObject is getting an object through JNDI lookup on the WebLogic Server. The JVM ("JVMName") needs to be registered in the registry, as described in step 3.
regjvmcmd JVMName localhost[7050]
DCOM Early Bound Programming Model
The basic client-side programming steps required to implement a DCOM early bound programming model are (described below for a VB client accessing an EJB on the WebLogic Server):
midl generatedIDLFileName.idl
The result of the compilation is a type library of the same name, but with the extension .tlb.
regtlb /unregisterall
regtlb generatedIDLFileName.tlb JVMName
The first line above calls regtlb.exe in order to un-register any previously registered type library versions. The second line then registers the newly compiled type library and specifies the name of the JVM ("JVMName") that will be linked with the type library. The WebLogic jCOM runtime requires this information for linking type library defined object calls to the appropriate wrapper classes.
Dim objCOM As generatedIDLFileName.generated class name
For example, if your fully qualified Java class is examples.ejb.basic.containerManaged.AccountHome, your generated class name would be ExampleEjbBasicContainerManagedAccountHome.
Dim objTemp As Object
Dim objBridge As New generatedIDLFileName.COMtoWebLogic
Set objTemp = GetObject("JVMName:jndi name of ejb")
Set objHome = objBridge.narrow(objTemp,"fully qualified java class")
Notice the objTemp object uses a late bound method to obtain a reference to the EJB object. This late bound object is passed to the bridge's "narrow" method, and is given an early bound object in return.
regjvmcmd JVMName localhost[7050]
DCOM Late Bound Encapsulation Programming Model
Using late bound encapsulation allows you to retain the majority of the benefits of early bound programming, while implementing a more flexible late bound model that does not require wrappers or type libraries.
For example, if you have a Visual Basic client accessing an EJB, you will need to do the following:
midl generatedIDLFileName.idl
The result of the compilation is a type library of the same name, but with the extension .tlb.
regtlb /unregisterall
regtlb generatedIDLFileName.tlb JVMName
The first line above calls regtlb.exe in order to un-register any previously registered type library versions. The second line then registers the newly compiled type library and specifies the name of the JVM ("JVMName") that will be linked with the type library. The WebLogic jCOM runtime requires this information for linking type library defined object calls to the appropriate wrapper classes.
For example, if your fully qualified Java class is examples.ejb.basic.containerManaged.AccountHome, your generated class name would be ExampleEjbBasicContainerManagedAccountHome.
Once you have done this, you can instantiate an instance of the class you've created, and access all of your EJB functionality as though it were early bound. Any changes to the EJB will not affect your VB project so long as the interface remains static for the methods and properties employed in the VB client source.
Native Mode Programming Model
In native mode a COM client accesses a Java object running on the same machine as the client. WebLogic jCOM uses native code to facilitate the interaction. For more on native mode see Native Mode in the Reference Guide.
Intercepting the Instantiation of Java Objects
If you wish to control the instantiation of Java objects, create a class which implements the com.bea.jcom.Instanciator interface. This interface has one method, which looks like this:
public Object instanciate(String javaClass) throws com.bea.jcom.AutomationException;
Pass a reference to your instantiator as a second parameter when calling Jvm.register(...):
com.bea.jcom.Jvm.register("MyJvm", myInstanciator);
The default instantiator used by WebLogic jCOM looks like this:
public final class DefaultInstanciator implements com.bea.jcom.Instanciator { public Object instanciate(String javaClass) throws com.bea.jcom.AutomationException { try { return Class.forName(javaClass).newInstance(); } catch(Exception e) { e.printStackTrace(); throw new AutomationException(e); } } }
For example this is a VB to EJB bridge (based on Sun's JNDI Tutorial):
import javax.naming.*; import java.util.Hashtable; import com.bea.jcom.*;
public class VBtoEJB { public static void main(String[] args) throws Exception { Jvm.register("ejb", new EjbInstanciator()); Thread.sleep(10000000); } }
class EjbInstanciator implements Instanciator { Context ctx;
EjbInstanciator() 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 { try { return Class.forName(javaClass).newInstance(); } catch(Exception e) {} return ctx.lookup(javaClass); } catch (Throwable t) { t.printStackTrace(); throw new AutomationException(new Exception("Unexpected: " + t)); } } }
If you compiled the above, and ran it on a machine (development.company.com) like this:
java -DJCOM_DCOM_PORT=4321 VBtoEJB
Then on a Windows machine you used the WebLogic jCOM regjvmcmd command like this:
regjvmcmd ejb development.company.com[4321]
Then from VB you would then use:
Set myEjb = GetObject("ejb:cn=ObjectName") MsgBox myEjb.someProperty myEjb.myMethod "a parameter"
Instantiating Java Objects from COM using Constructors
COM has no concept of constructors. One method is to define a default constructor, and then define a static member which takes the appropriate parameters and instantiates the object and returns it:
public class MyClass { public MyClass() {} public MyClass(String p1, int p2, double p3) { ... }
public static MyClass createMyClass(String p1, int p2, double p3) { return new MyClass(p1, p2, p3); } }
Another possibility is to use WebLogic jCOM's instantiation interception capability -- when you register the JVM you can pass a reference to an object whose class implements a special Java jCOM interface which is called when you use GetObject("MyJvm:MyClass") -- you get passed everything after the colon, so you could actually do: GetObject("MyJvm:MyClass(1, 2, three, 4.0") and then in the interceptor parse the string that is passed in, and invoke the appropriate constructor.
Implementing a Singleton Java Object
In COM terminology an object is a singleton if there exists only one instance of the object at any time. Each time you call CreateInstance you obtain a reference to the same object. This ensures that all clients access the same instance.
By controlling the instantiation of Java objects you can implement a singleton Java object which is accessible from COM clients. Here is an example of what the instantiator would look like for a class called mySingletonClass:
import java.util.*; import com.bea.jcom.*;
public class COMtoJava { public static void main(String[] args) throws Exception { try { Jvm.register("MyJvmId", new SingletonInstanciator("MySingletonClass"));
while (true) { // wait forever Thread.sleep(100000); } } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } }
class SingletonInstanciator implements Instanciator { String singletonClassname; static Object singletonObject = null;
SingletonInstanciator(String singletonClassname) { try { this.singletonClassname = singletonClassname; if (singletonObject == null) { System.out.println("SingletonInstanciator: creating the singleton [" + singletonClassname + "]"); // initialize the singleton Class classObject = Class.forName(singletonClassname); singletonObject = classObject.newInstance(); } } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } }
public Object instanciate(String javaClass) throws AutomationException { try { System.out.println("instanciate for " + javaClass);
// if request is to create the singleton, just return the existing instance. if (javaClass.equals(singletonClassname)) { return singletonObject; } else { Class classObject = Class.forName(javaClass); return classObject.newInstance(); } } catch (Exception e) { System.out.println("Failed to instanciate class " + javaClass); System.out.println(e.getMessage()); e.printStackTrace(); System.out.println("Throwing exception back to caller."); throw new AutomationException(e); } } }
And here is a sample MySingletonClass implementation:
public class MySingletonClass { public MySingletonClass() { System.out.println("MySingletonClass constructor called."); }
public int Method1(int val) { return val + 1; } }
If you compiled both of the above, and ran COMtoJava on a machine (development.company.com) like this:
java -DJCOM_DCOM_PORT=4321 COMtoJava
Then on a Windows machine you used the WebLogic jCOM regjvmcmd command like this:
regjvmcmd MyJvmId development.company.com[4321]
Then from VB you would then use:
Set objMySingleton1 = GetObject("MyJvmId:mySingletonClass") Set objMySingleton2 = GetObject("MyJvmId:mySingletonClass") MsgBox objMySingleton1 & objMySingleton2
Which would create two references to the same object.
|
Copyright © 2001 BEA Systems, Inc. All rights reserved.
|