[Previous] [Contents] [Next]

COM+ Programming in Java

Although one major goal of COM+ is to be programming-language neutral, COM+ programming has until recently been almost exclusively the domain of C++. As you know, COM+ programming in C++ is not for the faint of heart. Many developers who do COM+ programming use Visual C++, its wizards, and MFC. Although this makes COM+ programming significantly easier, it also means you have to wade through thousands of lines of code you didn't write and don't understand. Although you can use Visual Basic to build COM+ components, some developers don't consider Visual Basic a serious contender in the COM+ programming arena. Instead, they often use Visual Basic as a "glue" language to combine components created in lower-level languages such as C++.

Microsoft realized that with some decent development tools, Java would make a great programming language for building and using COM+ components. Visual J++ is Microsoft's answer to both of these ideas; it is a great Integrated Development Environment (IDE) for Java development and provides Java with access to COM+ capabilities.

What is it about Java that makes it so great for COM+ programming? The following table shows that although Java and COM+ were developed completely independently, they are complementary technologies. COM+ is an architecture for building components, while Java is a great programming language for building and using those components. You might be surprised to see COM+ described as simple. The original ideas of COM+ certainly are simple, but its implementation and use from languages such as C++ makes people think it's complicated. Once you start programming COM+ in Java, you'll see why COM+ is simple.

CharacteristicJavaCOM+
Programming languageYesNo
Language-independent component architectureNoYes
Virtual machineYesNo
SimpleYesYes
RobustYesYes
Object-orientedYesYes
Platform-independentYesYes
General-purposeYesYes
MultithreadedYesYes
DistributedNo (but Java 1.1 supports Remote Method Invocation [RMI])Yes

In computing, diametrically opposed technologies are often forced to coexist. As you'll see, Microsoft has integrated COM+ and Java very cleanly, in a manner that does not conflict with the spirit of Java in any way and does not add any new keywords or constructs to Java. Java already has the necessary constructs for implementing and using COM+ objects. Most of the changes that Microsoft has made to support the Java/COM+ integration model have been in Microsoft's Java Virtual Machine (msjava.dll). A Java Virtual Machine is a module that translates binary .class5 files from Java bytecode intonative op-codes for execution on a particular platform.

To access COM+ objects from a Java application, you simply open a project in Visual J++ and choose Project/Add COM Wrapper. Visual J++ then goes through the HKEY_CLASSES_ROOT\TypeLib key in the registry looking for all components containing valid type library information. This information is displayed in the COM Wrappers dialog box, shown in Figure 3-9. Each entry is shown with the user-friendly name found in the version number key for the type library settings—normally the helpstring parameter for the library found in the IDL file.

Click to view at full size.

Figure 3-9. The COM Wrappers dialog box enables Java applications to call COM+ components.

It is important to understand that Java support for COM+ is based on type libraries—a Java program can call any COM+ object for which type library information is available. This information might be available as a .tlb file or might be embedded as a resource within the component.

Let's say that you want to call a particular component from a program written in Java. The first step is to use the COM Wrappers dialog box to create Java class wrappers for the COM+ classes in the component. You simply add a check mark next to the components you want to use and then click OK. Visual J++ automatically converts the type library information to Java source files. 6 If you think about it, this is rather amazing: Visual J++ inputs the information contained in a type library and spits out Java source files—one for each class and interface described by the type library. By default, these source files are placed in a new subdirectory with the same name as the type library.

Each Java file generated by Visual J++ contains special Javadoc-style comments identifying it as a wrapper for a coclass. The comments take the form of /** @com and so are often referred to as @com comments. Listing 3-6 shows the isum.java file produced when Visual J++ generates wrappers for the Inside COM+ Component Type Library we built in Chapter 2. The Visual J++ compiler recognizes the special @com Javadoc-style syntax and emits .class files containing special attributes that indicate that the application is invoking COM+ objects. Typically, you don't need to code the @com directives yourself because Visual J++ contains wizards that generate these wrappers based on the information contained in a type library. However, to better understand the Java/COM+ integration model, let's examine the COM+ directives supported by Visual J++, which are shown in the following table:

DirectiveDescription
@com.class(GUID, security, casting)Specifies that the Java class represents a coclass with the given GUID, casting support, and Java security requirements.
@com.interface(GUID, thread, type)Indicates that the Java interface represents a COM+ interface with the specified GUID, threading model, and types.
@com.method(dispid, vtable, …)Marks the Java method as a COM+ interface method, which should be exposed in the object's v-table, dispatch table, or neither.
@com.parametersSpecifies which parameters are in, out, or a return value and how they should be mapped to COM+ and from COM+ to Java.
@com.typeinfoSpecifies additional information from the type library that represents this coclass.
@com.transactionSpecifies the transaction support required of the COM+ run-time environment.
@com.structSpecifies that the Java class is a Java-Callable Data Wrapper (JCDW). (JCDWs are proxies for external data structures, such as structs, unions, and arrays.)
@com.structmapIndicates how the field in a JCDW should map to COM+ and from COM+ back to this field in Java. You can also use this directive to custom marshal the data between Java and COM+ and to specify the data's offset from the beginning of the JCDW.

You might wonder how a program can cross the bridge from Java bytecode to a COM+ object. Well, when the Microsoft Java VM sees these special COM+ attributes in a class, it translates all Java method invocations on the class into calls to the specified coclass. So the Microsoft Java VM is actually the bridge between Java and COM+. For this reason, Java programs that use COM+ components work only on platforms supported by the Microsoft Java VM (at least for now).

isum.java

//
// Auto-generated using JActiveX.EXE 5.00.2918
//   ("C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\
//    VJ98\jactivex.exe" /wfc  /w /xi /X:rkc /l
//    "C:\WINDOWS\TEMP\jvc12F4.TMP" /nologo /d
//    "C:\My Documents\Visual Studio Projects\JavaClient" 
//    "C:\COMPONENT.DLL")
//
// 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 component;

import com.ms.com.*;
import com.ms.com.IUnknown;
import com.ms.com.Variant;

// VTable-only interface ISum
/** @com.interface(iid=10000001-0000-0000-0000-000000000001, 
    thread=AUTO) */
public interface ISum extends IUnknown
{
    /** @com.method(vtoffset=0, addFlagsVtable=4)
        @com.parameters([in,type=I4] x, [in,type=I4] y, 
        [type=I4] return) */
    public int Sum(int x, int y);


    public static final com.ms.com._Guid iid = new 
        com.ms.com._Guid((int)0x10000001, (short)0x0, 
        (short)0x0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, 
        (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x1); 
}

Listing 3-6. The COM+ wrapper for the ISum interface generated by Visual J++ when a Java application imports the type library of the component created in Chapter 2.

Several items are worth noting about the generated wrapper files. The ISum interface defined in the isum.java source file extends (Java lingo for "derives from") the IUnknown interface. At last, our friend IUnknown! The InsideCOM class declared in the insidecom.java wrapper file, shown in Listing 3-7, implements the IUnknown and ISum interfaces. In Java, the extends keyword enables single inheritance among classes or interfaces, while the implements keyword enables a class to support multiple interfaces—which is crucial for supporting COM+. The GUIDs for the ISum interface and the InsideCOM coclass are also declared in the wrapper files, both in the @com Javadoc comments and as constants in the class and interface definitions.

insidecom.java

//
// Auto-generated using JActiveX.EXE 5.00.2918
//   ("C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\ 
//    VJ98\jactivex.exe" /wfc  /w /xi /X:rkc /l 
//    "C:\WINDOWS\TEMP\jvc4120.TMP" /nologo /d
//    "C:\My Documents\Visual Studio Projects\JavaClient" 
//    "C:\COMPONENT.DLL")
//
// 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 component;

import com.ms.com.*;
import com.ms.com.IUnknown;
import com.ms.com.Variant;

/** @com.class(classid=10000002-0000-0000-0000-000000000001,
    DynamicCasts) 
    @com.interface(iid=10000001-0000-0000-0000-000000000001, 
    thread=AUTO) */
public class InsideCOM implements IUnknown, 
    com.ms.com.NoAutoScripting, component.ISum

{
    /** @com.method(vtoffset=0, addFlagsVtable=4)
        @com.parameters([in,type=I4] x, [in,type=I4] y, 
        [type=I4] return) */
    public native int Sum(int x, int y);


    public static final com.ms.com._Guid iid = new 
        com.ms.com._Guid((int)0x10000001, (short)0x0, (short)0x0, 
        (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, 
        (byte)0x0, (byte)0x0, (byte)0x1);

    public static final com.ms.com._Guid clsid = new 
        com.ms.com._Guid((int)0x10000002, (short)0x0, 
        (short)0x0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, 
        (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x1);
}

Listing 3-7. The COM+ wrapper for the InsideCOM coclass generated by Visual J++ when a Java application imports the type library of the component created in Chapter 2.

Calling a COM+ Object from Java

When you use the Java-callable wrappers for COM+ objects, you must always invoke methods through an interface, not through the class itself (just as COM+ objects are always called through an interface in C++). Listing 3-8 shows a simple Java program that instantiates the InsideCOM coclass and then invokes methods of the ISum interface.

javaclient.java

/**
 * This class can take a variable number of parameters on the 
 * command line. Program execution begins with the main()
 * method. The class constructor is not invoked unless an 
 * object of type 'Class1' created in the main() method.
 */

import component.*;

public class JavaClient
{
    /**
     * 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)
    {
        // TODO: Add initialization code here
        ISum myRef = (ISum)new InsideCOM();
        int result = myRef.Sum(5, 4);
        System.out.println(
            "Java client: myRef.Sum(5, 4) returns " 
            + result);
    }
}

Listing 3-8. A Java client application that invokes the InsideCOM coclass implemented in C++.

As in the Visual Basic code presented earlier, you won't recognize any COM+ function calls in this code—no CoInitializeEx, no CoCreateInstance(Ex), and no IUnknown methods such as QueryInterface. The import statement makes accessible the compiled version of the generated COM+ wrapper files in the component subfolder. Note that this statement is not analogous to the C++ #import directive that generates code based on the contents of a type library—although the name of the C++ directive was inspired by the Java statement. In Java, you can reference any class using its fully qualified name (for example, component.InsideCOM) if the class can be found in the classpath (the path the compiler uses to find packages referenced in a Java application). The import statement simply lets you refer to the class using its short name (such as InsideCOM). If the class name is qualified by the package name (component.InsideCOM), the import statement is not needed.

Java's new keyword instantiates the InsideCOM class. This instantiation leads the Microsoft Java VM into the insidecom.class file generated by Visual J++, where the Microsoft Java VM encounters special attributes indicating that this is a coclass wrapper. The generated .class file also contains the CLSID of the coclass. The Microsoft Java VM then uses that CLSID to call CoCreateInstance(Ex). The IUnknown pointer returned by CoCreateInstance(Ex) is then cast by the Java code to ISum, as shown here:

ISum myRef = (ISum)new InsideCOM();

Hidden from view is the call to the IUnknown::QueryInterface function that lets clients choose among an object's supported interfaces. The simple typecast from the InsideCOM class to the ISum interface forces the Microsoft Java VM to call the object's QueryInterface function to request a pointer to ISum. In this manner, a Java program can retrieve an interface pointer to any interface supported by a COM+ object. Simply casting the object to the appropriate interface yields correct results.

If the object does not implement the requested interface and the QueryInterface call fails, an exception of type java.lang.ClassCastException is thrown when you attempt the cast. One option is simply to catch this exception using Java's exception handling mechanism. To determine whether an object implements the desired interface before casting, you can use the instanceof operator, as shown in the following code:

IUnknown myRef = new InsideCOM();
if(myRef instanceof ISum)
{
    // Now we know that InsideCOM implements ISum.
    // It is safe to cast (ISum)myRef.
}

To instantiate an object on a remote machine, client applications can rely on the RemoteServerName registry setting to specify the name of the machine on which the object should be created. (This setting is described in detail in Chapter 12.) Alternatively, Java applications can directly invoke the CoCreateInstanceEx function using J/Direct, the facility that Java developers can use to make direct calls to functions exported by DLLs. A client application using CoCreateInstanceEx has much greater flexibility than that permitted by the registry settings. The code fragment below shows how to call CoCreateInstanceEx from Java:

int HRESULT = 0;

// Set up the CoServerInfo structure to specify the 
// machine name and security info
com.ms.com.COSERVERINFO ServerInfo =  
    new com.ms.com.COSERVERINFO();
ser.pwszName = "ServerMachine";

// Set up the MULTI_QI structure to request certain interfaces
com.ms.com.MULTI_QI qi = new com.ms.com.MULTI_QI();
qi.pIID = 
    com.ms.com.ComLib.getGuidOf(com.ms.com.IUnknown.class);

// Call CoCreateInstanceEx
HRESULT = com.ms.win32.Ole32.CoCreateInstanceEx(
    new com.ms.com._Guid(CLSID_InsideCOM), null, 
    com.ms.win32.win.CLSCTX_REMOTE_SERVER, ServerInfo, 1, 
    new com.ms.com.MULTI_QI[]{qi});

Reference counting, another painful COM+ chore, is handled automatically in Java. As with the smart interface pointers in Visual C++, you do not need to call IUnknown::AddRef when you create a new reference to an object, nor do you need to call IUnknown::Release when you finish using a reference to an object. As it does for native Java objects, the garbage collector performs reference counting automatically and calls the Release method on object references that go out of scope. Setting an interface reference to null, as shown below, can trigger Java's garbage collection algorithm:

myRef = null;

The Java garbage collection mechanism is not guaranteed because many COM+ objects can be called only on the thread on which they were created. Because garbage collection can occur at unpredictable times, the required thread might have expired by the time garbage-collection reclaims the object; this can result in memory leaks and tie up other system resources. You should therefore explicitly free COM+ objects in a timely and predictable fashion. You can use the com.ms.com.ComLib.release method to force Java to release all its reference counts on a COM+ object, as shown here:

ComLib.release(myRef);

Building a Client in Java

To build a COM+ client program in Java, follow these steps:

  1. Open Visual J++.
  2. Choose File/New Project.
  3. Click the New tab, and then select the Applications folder and the Console Application project type.
  4. In the Name text box, type TestCOM, and click Open.
  5. Choose Project/Add COM Wrapper.
  6. Select the Inside COM+ Component Type Library check box, and click OK.
  7. Open the class1.java source file.
  8. Modify the class template by adding the code shown here in boldface:
  9. /**
     * This class can take a variable number of parameters on 
     * the command line. Program execution begins with the main()
     * method. The class constructor is not invoked unless an  
     * object of type 'Class1' created in the main() method.
     */
    import component.*;
    
    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)
        {
            // TODO: Add initialization code here
            ISum myRef = (ISum)new InsideCOM();
            int result = myRef.Sum(5, 4);
            System.out.println(
                "Java client: myRef.Sum(5, 4) returns " 
                + result);
         }
    }
    

  10. Choose Debug/Start to run the application.

Implementing COM+ Objects in Java

Up to now, we have examined how to call COM+ objects built in C++ from Java. You can also implement COM+ objects in Java. These components can be called from languages such as C++ and Visual Basic as well as from Java itself. Like the rest of the Java/COM+ integration model, this functionality has been implemented cleanly. Let's say you want to implement the ISum interface in Java. The steps involved are shown below:

  1. Define the interfaces and coclasses in IDL.
  2. Convert the IDL file into a type library using the MIDL compiler.
  3. Generate Java wrappers for the interfaces and coclasses defined in the type library.
  4. Build Java classes that implement the desired interfaces.

Recall that all COM+ programming should begin in IDL. When you implement COM+ interfaces in Java, you must first define the interfaces in IDL. For the Java project, you can reuse the component.idl file created for the C++ component and presented earlier in Listing 3-1. Then you implement the ISum interface in Java, as shown in Listing 3-9. Notice that the class and the Sum method are declared as public so that they are accessible from outside the package.

class1.java

/**
 * @com.register ( clsid=FDDA9DC0-B472-11D2-BB50-006097B5EAFC, 
       typelib=FDDA9DC1-B472-11D2-BB50-006097B5EAFC )
 */
public class Class1 implements component.ISum
{
    public int Sum(int x, int y)
    {
        return x + y;
    }
}

Listing 3-9. A Java implementation of the ISum interface.

In order for a client to invoke a Java class via COM+, the Microsoft Java VM must dynamically create a COM+ callable wrapper object that exposes the functionality of the Java class. The Microsoft Java VM contains what is essentially a generic COM+ object with a virtual function table that is constructed dynamically to support several standard COM+ interfaces as well as any COM+ interfaces implemented by the Java class. (For more on how virtual function tables can be constructed dynamically, see Chapter 8.) The COM+ callable wrapper object implemented by the Microsoft Java VM also supports aggregation, which means that any COM+ object written in Java can be aggregated, although COM+ objects written in Java cannot aggregate other COM+ objects. The Microsoft Java VM provides default implementations of the following interfaces for COM+ components written in Java:

InterfaceDescription
IUnknownHandles QueryInterface and reference counting for all COM+ objects. See Chapter 2
IDispatch and IDispatchExProvides Automation support. See Chapter 5.
IProvideClassInfo and IProvideClassInfo2Provides a method for accessing the type information for an object's coclass entry in its type library. See Chapter 9.
ISupportErrorInfoEnsures that error information can be correctly propagated up the call chain. See Chapter 6.
IConnectionPointContainerSupports connection points for connectable objects. See Chapter 8.
IExternalConnectionManages an object's count of marshaled (external) references, enabling the object to detect when it has no external connections so that it can shut down properly. See Chapter 13.
IMarshalSpecifies how a COM+ object can be marshaled between processes and computers. See Chapter 14.

With Visual Basic, developers are basically stuck with the default implementations of these standard interfaces provided by the Visual Basic VM. Java developers, in contrast, can provide custom implementations for most7 of these interfaces simply by implementing them. Like Visual Basic, the Microsoft Java VM also provides class objects for each coclass. These class objects implement the IClassFactory interface and support standard IClassFactory::CreateInstance semantics.

Packaging and Registering Java Components

The binary files produced by Java compilers containing Java bytecode are saved with the .class file extension. However, this is not necessarily the best medium for distributing a Java application. Typically, the collection of .class files that make up an application or component are packaged together. Visual J++ offers several packaging options, which are shown in the following table:

Packaging TypeDescription
COM DLL (.dll)A COM+ in-process component.
Windows EXE (.exe)A standard Win32 application in Portable Executable (PE) file format.
Cab Archive (.cab)A cabinet file, which is an efficient way to package multiple files to ensure efficient download and installation of Java packages and classes executed on (or behind) HTML in Internet Explorer.
Self-extracting Setup (.exe)A self-extracting setup executable file, which provides a mechanism to distribute a stand-alone application to users. The setup also includes an uninstalling program.
Zip Archive (.zip)A file that packages multiple files (such as Java packages and classes) in a single, uncompressed file that is compatible with Internet Explorer and other browsers.

When you build a COM+ component in Visual J++, the .class files that make up that component are packaged together inside one .dll file, and the component generated automatically supports the standard COM+ exported functions, including built-in self-registration via the DllRegisterServer and DllUnregisterServer functions. As expected, after registration the InprocServer32 entry in the HKEY_CLASSES_ROOT\CLSID section of the registry points to the component built in Visual J++. You'll find it helpful, however, to turn off the packaging feature of Visual J++ and view the raw registry entries created for the .class files built in Java.

Shown below are the most interesting registry entries created during the build process when packaging has been disabled. Notice that the InprocServer32 key for the JavaComponent component is listed as msjava.dll—the Microsoft Java VM! Because Java code is compiled into bytecode, it can't be called directly from a language such as C++. Instead, the Microsoft Java VM provides the COM+ support for your Java programs. Client applications think they are working directly with your component, but they are actually working with msjava.dll, which actually runs your Java code. When packaged as a COM+ DLL, the same basic mechanism is at work, but the .class files are wrapped in a .dll file that simply loads the Microsoft Java VM and proceeds as usual.

[HKEY_CLASSES_ROOT\CLSID\{FDDA9DC0-B472-11D2-BB50-006097B5EAFC}\
    InprocServer32]
@="C:\WINDOWS\SYSTEM\MSJAVA.DLL"
"CodeBase"="file:C:\My Documents\JavaComponent\"
"JavaClass"="Class1"
"ThreadingModel"="Both"

The JavaClass value names the Java class that is to be exposed as a COM+ object. The CodeBase value specifies a path that should be added to the classpath when the object is created. This helps ensure that the class named by the JavaClass value can be located and accessed.

Building a Component in Java

To build a COM+ component in Java, follow these steps:

  1. Open Visual J++.
  2. Create a new component project by selecting COM DLL in the Components folder on the New tab of the New Project dialog box. Name the project JavaComponent and click Open.
  3. Choose Project/Add COM Wrapper.
  4. Select the Inside COM+ Component Type Library item, and click OK.
  5. Modify the class1.java file so that it looks as follows. (The changes are shown in boldface.)
  6. /**
     * This class is designed to be packaged with a COM DLL 
     * output format. The class has no standard entry points, 
     * other than the constructor. Public methods will be exposed 
     * as methods on the default COM interface.
     * @com.register ( clsid=FDDA9DC0-B472-11D2-BB50-006097B5EAFC, 
           typelib=FDDA9DC1-B472-11D2-BB50-006097B5EAFC )
     */
    public class Class1 implements component.ISum
    {
        // TODO: Add additional methods and code here
        public int Sum(int x, int y)
            {
                return x + y;
            }
    
         /**
         * NOTE: To add auto-registration code, refer to the 
         * documentation on the following method
         *   public static void onCOMRegister(boolean unRegister) {}
         */
    }
    

Choose File/Save Class1.java.

Choose Build/Build.

To test this Visual J++ component from C++, you can use the easyclient.cpp program in Listing 3-3 as a starting point or enter the code shown in Listing 3-10. Otherwise, you can use Visual Basic or Java itself to build a client for this component.

jclient.cpp

#import "JavaComponent.dll" no_namespace
#import "component.dll" no_namespace
#include <iostream.h>

void main()
{
    CoInitialize(NULL);
    ISumPtr myRef(__uuidof(Class1));
    int result = myRef->Sum(5, 13);
    cout << "5 + 13 = " << result << endl;
    myRef = NULL;
    CoUninitialize();
}

Listing 3-10. A C++ client that uses the COM+ component created in Java.

ActiveX Controls and JavaBeans Integration

To enable Java developers to use the thousands of commercially available ActiveX controls, Microsoft has extended its Microsoft Java VM so that ActiveX controls can be hosted in a Java applet or application. The Microsoft Java VM also lets you expose JavaBeans components as ActiveX controls. These components, which are designed for Java, might eventually compete with ActiveX controls in the marketplace of reusable components. As compelling JavaBeans components become commercially available, they will immediately be usable by the large number of ActiveX control containers such as Visual Basic, Visual C++, Borland Delphi, and Powersoft PowerBuilder.

Thus, an ActiveX control appears as a JavaBeans component to a Java programmer, and a JavaBeans component appears as an ActiveX control to a developer using any of the wide array of development tools that support COM+. The Microsoft Java VM is the bridge that makes this bidirectional support possible. Developers can work in the environment with which they are most familiar and still take advantage of all available components, regardless of the development tools or platforms used to build them.

Exposing an existing JavaBeans component as an ActiveX control is as simple as running the JavaReg utility to register the control and generate a type library that describes its properties, methods, and events. After you run JavaReg, the JavaBeans component looks and functions just like a native ActiveX control in any control container. For example, a Visual Basic application can take advantage of a JavaBeans component that has been turned into an ActiveX control.

The Sandbox Model

Because a user can automatically download Java applets from Web sites, security is a big concern. To prevent Java applets from potentially damaging the user's system, applets typically run in a sandbox—a carefully delimited execution environment that prevents applets from posing a security threat. Local file access, for example, is off limits. COM+ services are also not available to applets running in the sandbox. Note that the sandbox restriction applies only to applets; standard Java applications do not run in the sandbox and therefore might use COM+ services. Running applets in the sandbox is a necessary for security reasons, but the restrictions imposed by the sandbox prevent applets from doing many useful and interesting things, such as accessing COM+ services. To overcome this limitation, the Microsoft Java VM categorizes applets as either trusted or untrusted.

Untrusted applets run within the sandbox and cannot use COM+ services, as is the norm for untrusted applets. All .class files that aren't loaded from the class path—including those downloaded from the Internet—are considered untrusted. Trusted .class files are those that are either loaded from the class path or extracted from a cabinet (.cab) file that has a digital signature. By using .cab files, you can designate Java applets downloaded from the Internet as trusted. Trusted applets run outside of the security sandbox; they can therefore read and write files and use COM+ services.

Four path-related registry values are relevant to the security of Java applets. These values are stored in the HKEY_LOCAL_MACHINE\SOFTWARE \Microsoft\Java VM key. The names and typical values are shown here:

Classpath = "C:\WINDOWS\java\classes;."
LibsDirectory = "C:\WINDOWS\java\lib"
TrustedClasspath = ""
TrustedLibsDirectory = "C:\WINDOWS\java\trustlib"

During development in Visual J++, all .class files are considered trusted, so you don't have to worry about security issues. If you want to distribute a Java applet that uses COM+ services over the Internet, you must ensure that your applet runs outside of the sandbox on the user's machine. To do so, you can create digitally signed .cab files for your Java classes using the cabinet and code signing tools in the Platform SDK. In addition to enabling applets to run outside the sandbox, using .cab files for your classes speeds up downloading and makes installation more secure. Windows applications and COM+ components written in Java that do not run in a Web browser and are not downloaded over the Internet are automatically executed outside the sandbox and can therefore use COM+ services.