Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JVM Languages

Can You Implement COM Components Using Java?


Jun00: Java Q&A

Jacob is a corporate MIS manager. He can be reached at [email protected].


Until the late 1980s, applications were predominantly written in procedural programming languages such as C and Pascal. These languages only had primitive mechanisms to facilitate code reusability. Object-oriented languages such as C++ and Java introduced the concepts of classes, encapsulation, inheritance, and polymorphism to make it easy for programmers to develop reusable source code. However, with the exception of Java, object-oriented programming languages such as C++ provide little to develop reusable binary objects. Being able to share binary components between multiple applications is referred to as "component-based programming" and Microsoft's Component Object Model (COM) is one approach for implementing reusable binaries that can be shared between applications across systems.

Today, most COM components are implemented in C++ and Visual Basic. In this article, however, I'll examine how you can implement COM components in Java.

Pros and Cons of Java-Based COM Components

Why would you use Java to create COM components? First of all, Java is a great language to work in. Unlike Visual C++, it enforces object-oriented programming. It is more powerful than Visual Basic, but not as hard to learn and use as Visual C++. If you have ever implemented a COM component in C++, you will agree that it is not a trivial task -- even if you take advantage of the Active Template Library (ATL).

One of the reasons for the reduced complexity is that the Microsoft Virtual Machine (MSVM) provides functionality that otherwise needs to be implemented by the client. For instance, the MSVM takes care of reference counting, eliminating the need for calling AddRef(). The Java garbage collection takes care of objects that are no longer in use. The MSVM aside, Visual J++ 6.0 and its wizards reduce the complexity of developing and using COM components.

On the downside, COM clients that use Java-based COM components need to have a compatible version of the Microsoft Java Virtual Machine (MSJVM) installed, which requires additional memory. Additionally, Java-based COM objects are still somewhat slower than components written in C++.

The Microsoft Java Virtual Machine

COM components and Java objects are quite similar. Both support the concept of classes and interfaces. A Java class or interface belongs to a package. A COM class or interface belongs to a COM library. A COM library is the equivalent of a Java package. In Java, the classpath defines the location of the class files that a VM can load. Unlike COM, which has one set of COM classes for all applications on the same system, each Java VM can have different class paths. Java classes are uniquely identified by their fully qualified class names, such as java.util.date. COM classes and interfaces on the other hand are uniquely identified by a 128-bit GUID.

Despite the similarities between Java and COM, they represent two different worlds. It is the MSJVM that brings the two worlds together. To invoke a Java class via COM, the MSJVM dynamically creates a COM wrapper object that exposes the functionality of the Java class. The Java VM provides a COM object with a v-table that is dynamically constructed to support standard COM interfaces such as IUnknown and IDispatch, as well as interfaces implemented by the Java class.

Java code is compiled into bytecode and cannot be called directly from languages such as Visual Basic, C++, and VBScript. To call functions in COM components written in Java, the COM client loads MSJava.dll, which executes the bytecode in the Java class file. If a Java COM component was packaged as COM DLL using Visual J++, the client loads the COM DLL file, which then loads MSJava.dll to execute the Java bytecode.

Implementing Java Automation Objects Using AutoIDispatch

Since Microsoft VM 1.5, all Java objects are automatically COM objects. The Microsoft VM automatically presents a Java object as an Automation object through an IDispatch interface. This is called AutoIDispatch. If your component doesn't require a custom interface, and its primary use is in a scripting environment, you can use your Java class directly as a COM object without any programming.

Listing One(a) is the ADispatchSample .java example, which contains the SayHi() method and curDate property. To register the Java class file as a COM component, you need to compile the java file by executing jvc ADispatchSample.java, copy the resulting class file into the \winnt\ java\ trustlib directory of your web server, and register it as a COM object using the javareg .exe utility: javareg /register/ class:ADispatchSample/progid:ADispatchSample. The command javareg.exe will display the CLSID that was assigned to our component. Listing One(b) is an Active Server Pages (ASP) example, which uses the ADispatchSample object.

AutoIDispatch has several drawbacks. Because it only implements an Automation interface, performance is limited. Another limitation of AutoIDispatch is that the VM does not associate any Type Library information with the COM object. Therefore, Java and Visual Basic clients, which both require Type Library information, cannot use AutoIDispatch-based Java COM components.

Implementing a Java COM DLL in Visual J++

Listing Two(a) illustrates the tips.java sample file. Tips.java has two methods. getComTips() randomly returns tips about COM. GetASPTips() does the same for ASP.

To create the component, you need to create a new Project TipServer in Visual J++, and add the class tips.java to the project. After you enter the tips.java source code, go into the project properties and click on the COM tab. As displayed in Figure 1, select Automatically generate Type Library, and check the classes you want to be exposed as COM interfaces. As you can see in Listing Two(a), Visual J++ puts a comment @register.com {clsid clsid= 4F49E33D...} at the beginning of the class file. This directive tells Visual J++ that the Java class file is a COM component, and it will automatically register it in the registry of the local system during compilation. Before you build the project, you need to set the output format to COM DLL.

After compiling the project, you find this new component in the local registry under the HKEY_CLASSES_ROOT\CLSID folder. Visual J++ automatically generated a CLSID, assigned a program ID (TipServer.tips), and created a DLL file that includes the Type Library information for the TipServer class. To register it on another machine, copy TipServer.dll into the windows\system(32) directory and run regsvr32.exe TipServer.dll. Listing Two(b) shows an ASP example that uses the TipServer COM component.

If you look at the new component using the Visual J++ OLE View utility, it shows that you've just implemented an Automation object and, as such, it does not implement the fast Custom Interface. Additionally, it exposes all public methods of the Java class, including Java core functions such as wait() and notify().

Implementing an Existing Interface

To overcome these limitations, you need to find a way to convince Visual J++ to implement an interface definition you provide. All COM component development typically starts with the interface definition. Listing Three is the IDL file for a TipServer component that implements a Dual interface. As you can see, Dual interfaces are derived from IDispatch. A Dual interface implements both the fast v-table as well as the slow Automation calls. The GUIDs for the Interface, Type Library, and COM class in our DualTipServer.idl file were generated with the GUIDGEN.EXE Visual Studio utility. You use another Visual Studio tool, MIDL .EXE, to check the DualTipServer.idl file for errors: MIDL /Zs DualTipServer.idl.

To be able to use the interface just defined in Visual J++, you need to generate a Type Library file, using MIDL.EXE: MIDL /proxy nul /header nul /iid nul /dlldata nul /win32 DualTipServer.idl. You then copy the resulting TipServer.tlb file into the Visual J++ project directory. After you create a new project in Visual J++, right-click the TipServer project, press the COM Classes tab, and click Use Existing Type Library, as in Figure 1. You browse to the TipServer.tlb file, which has just been copied into the project directory. Before you exit the project property page, set the output format to COM DLL.

As you can see in Figure 2, Visual Studio has now added IDualTipServer.java, IDualTipServerDefault.java, as well as tips.java to the project. The first two Java files define the interfaces of the component. Each interface method is preceded with the @com.method Directive. It marks a Java method as a COM interface, which should be exposed in the object's v-table and dispatch table. Visual J++ evaluates the COM directives during compile time to register the component properly. The tips.java file provides a default implementation for GetComTips() and GetASPTips(). You need to replace the default implementation for these two methods with the source code. Listing Four shows the final tips.java file.

Calling a COM Component from Java

You are now able to create Java-based COM components with Automation, Custom, or Dual Interfaces. However, the method for calling COM objects within Java applications has yet to be discussed.

As you have seen, a COM object provides a pointer to a function table (v-table). However, Java doesn't support the concept of pointers. As a result, the v-table pointers cannot be accessed directly in Java. Fortunately, the MSVM creates a Java object that represents the COM object. Whenever you call one of the Java object methods, the MSVM translates the Java method call into a COM function call.

Listing Five shows a simple Java application that calls the COM object methods implemented in Listing One(a). To create the application, you need to open a new Console Application project in Visual J++ and add the Java class displayed in Listing Five to the project. You then select the Add COM Wrappers page from the Project menu. This page then displays the Type Library files of all COM components installed on the local system. Next, check the TipServer Type Library implemented in the second example, and click OK. You will notice that Visual J++ adds the tips.java and tips_Dispatch.java COM wrapper class files to the project. The COM wrapper class files are vital, because this Java application will call all COM interfaces and classes through them. Visual J++ automatically creates Java wrapper classes and interfaces for each COM class and interface that exists in the COM library that's added to the project.

COM+ and Windows 2000

COM+, the next version of COM, is an integral part of Windows 2000. Microsoft has added several features to COM+, making it a more robust and scalable technology.

For instance, Transaction Server is now an integral part of Windows 2000. Since its first release, one of Transaction Server's main responsibilities was managing COM components. It enables just-in-time activation and object pooling, two technologies that make COM+ a scalable solution. Transaction Server maintains a pool of objects that are shared by COM+ clients. Instead of creating a new instance for each client that requests a new object, Transaction Server assigns an object from a pool that is shared by all clients. Even better, when a COM client instantiates a COM object, COM+ creates a virtual context object and returns a reference to it, rather than a reference to the component itself. When the component is accessed, Transaction Server assigns an object from the component pool to the context object. As soon as the object is idle (not accessed) the object is returned to the pool to be used by other clients. To a COM client, it looks as if it still possesses the object, although it only owns the Context Object, which takes little resources.

For busy applications, just-in-time activation and object pooling may not be sufficient to handle the workload. Therefore, COM+ implemented component-level load balancing, which allows distributing the workload among multiple servers in a network. It also provides redundancy. If a client has a reference to a component on a server that goes down, COM+ automatically routes a client request to another server that belongs to the application cluster.

Like Transaction Server, Microsoft Message Queue Server (MSMQ) is part of Windows 2000. Using queued components, a client can easily execute methods against COM+ components, even if that component is currently unavailable.

DDJ

Listing One

(a)
// Source Code Start
import java.util.Date;
class ADispatchSample{
      public String SayHi(){
          return("Hi Dr.Dobb's reader!");
      }
      public Date curDate = (Date)new Date();
}

<b>(b) </b>
File name:   ADispatchTest.asp
-------------------------------

<%@ LANGUAGE="VBSCRIPT" %>

<html>
<head>
        <title>ADispatchTest</title>
</head>

<body>

<% 
    Set objADispatch = CreateObject("ADispatchSample")
%>

<%= objADispatch.SayHi()%>
<br><br>
<b>Today's date is:</b>  <%= objADispatch.curDate %>

<%  Set objADispatch = Nothing  %>

</body>
</html>

Back to Article

Listing Two

(a)
/** @com.register ( clsid=4F49E33D-A813-4171-97D9-EEE7AD9C2F69, 
typelib=136C0E92-AF90-4365-8071-47D52152762B ) */
public class tips
{
    private static String[] ComTips = {
     "An Automation interface is slower than a Custom Interface",
     "All COM objects are derived from IUnknown",
     "IUnknow Methods: QueryInterface(),AddRef() and Release()",
     "IDispatch Methods: GetIDsOfNames,Invoke(),GetTypeInfoCount,GetTypeInfo",
     "COM components can implement a 'Custom Interface', 
                                    Automation Interface or Dual Interface",
     "A GUID is 128bit unique identifier for a COM component",
     "If a progid is defined for a COM object, it can be used instead 
                                    of a CLSID to instantiate a COM object",
     "COM+ is the next incarnation of COM. It is part of Windows 2000"
    };
    private static String[] ASPTips = {
        "ASP stands for Active Server Pages",
        "The Response object returns information to the client!",
        "The Request object is used to get information from the client!",
        "ASP is used to call COM components from a scripting language",
        "The VBScript and JavaScriptscripting engine are part of Windows",
        "ASP supports sessions to maintain state information",
        "ASP sessions use cookies to maintain state"
    };
    public String getComTip(){
        return getTip(ComTips);
    }
    public String getASPTip(){
        return getTip(ASPTips);
    }
    private String getTip(String[] source){
        int index = (int)(Math.random() * source.length);
        return source[index];
    }
}

<b>(b)</b>
<%@ LANGUAGE="VBSCRIPT" %>
<html>

<head>
    <title>Tips Test</title>
</head>
<body>
<% 
    Set objTip = CreateObject("TipServer.tips")
%>
<b>COM Tip:</b><br>
<%= objTip.GetCOMTip()%>
<br><br>
<b>ASP Tip:</b><br>
<%= objTip.GetASPTip()%>
<%  Set objTip = Nothing %>
</body>
</html>

Back to Article

Listing Three

import "oaidl.idl";
import "ocidl.idl";
[ 
  object,
  uuid (3D7BFA13-EBF9-418c-B6A8-F2182E7AA03E),
  dual,
  helpstring("IDualTipServer Interface"),
  pointer_default(unique)
]
interface IDualTipServer : IDispatch
{
   HRESULT getComTip([out, retval] BSTR* ret);
   HRESULT getASPTip([out, retval] BSTR* ret);  
};
[
   uuid (7AF622C6-BD7F-4638-AB1B-82537FEABB38),
   version(1.0),
   helpstring("DualTipServer 1.0 Type Library")
]
library DualTipServerLib
{
   importlib("stdole32.tlb");
importlib("stdole2.tlb");
   [
      uuid (FF551EA5-812B-4297-8068-118ADE65E718),
      helpstring("DualTipServer Class")
   ]
   coclass tips
   {
      [default] interface IDualTipServer;
   }
};

Back to Article

Listing Four

// Auto-generated using JActiveX.EXE 5.00.2918
//   ("C:\Program Files\Microsoft Visual Studio\VJ98\jactivex.exe" 
          /javatlb /c2j /creg /xh /wfc  /w /xi /X:rkc /l 
          "C:\DOCUME~1\JGsoedl\LOCALS~1\Temp\jvc44.tmp" /nologo /d 
          "C:\Documents and Settings\JGsoedl\My Documents\Visual Studio 
           Projects\DualTipServer"
 "C:\Documents and Settings\JGsoedl\My Documents\Visual Studio Projects\
           DualTipServer\DualTipServer.tlb")
//
// WARNING: Do not remove the comments that include "@com" directives.
// This source file must be compiled by a @com-aware compiler.
// If you are using the Microsoft Visual J++ compiler, you must use
// version 1.02.3920 or later. Previous versions will not issue an error
// but will not generate COM-enabled class files.

package dualtipserver;
import com.ms.com.*;
import com.ms.com.IUnknown;
import com.ms.com.Variant;
/** @com.register(clsid=FF551EA5-812B-4297-8068-118ADE65E718, 
    typelib=7AF622C6-BD7F-4638-AB1B-82537FEABB38, version="1.0", 
    description="DualTipServer Class")*/
public class tips implements IUnknown,com.ms.com.NoAutoScripting,
    dualtipserver.IDualTipServerDefault
{
    private static String[] ComTips = {
     "An Automation interface is slower than a Custom Interface",
     "All COM objects are derived from IUnknown",
     "IUnknow Methods: QueryInterface(),AddRef() and Release()",
     "IDispatch Methods: GetIDsOfNames,Invoke(),GetTypeInfoCount,GetTypeInfo",
     "COM components can implement a 'Custom Interface', 
                               Automation Interface or Dual Interface",
     "A GUID is 128bit unique identifier for a COM component",
     "If a progid is defined for a COM object, it can be used instead 
                               of a CLSID to instantiate a COM object",
     "COM+ is the next incarnation of COM. It is part of Windows 2000"
    };
    private static String[] ASPTips = {
        "ASP stands for Active Server Pages",
        "The Response object returns information to the client!",
        "The Request object is used to get information from the client!",
        "ASP is used to call COM components from a scripting language",
        "The VBScript and JavaScriptscripting engine are part of Windows",
        "ASP supports sessions to maintain state information",
        "ASP sessions use cookies to maintain state"
    };
    public String getComTip() {
        return getTip(ComTips);
    }
    public String getASPTip() {
        return getTip(ASPTips);
    }
    private String getTip(String[] source){
        int index = (int)(Math.random() * source.length);
        return source[index];
    }
}

Back to Article

Listing Five

/** This class can take a variable number of parameters on the command line.
 * Program execution begins with the main() method. Class constructor is not 
 * invoked unless an object of type 'Class1' created in the main() method.
 */
import tipserver.*;
public class Class1
{
    /** The main entry point for the application. 
     * @param args Array of parameters passed to the application
     * via the command line. */
   public static void main (String[] args)
    {
        tips objTips = new tipserver.tips();
        String aspTip = objTips.getASPTip();
        String ComTip = objTips.getComTip();
        System.out.println("\n\nToday's ASP Tip: " + aspTip);
        System.out.println("Today's COM Tip: " + ComTip + "\n\n");
    }
}

Back to Article


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.