An API for caffeinating your native application!

by Gennaro (Jerry) Cuomo, Michael Fraenkel and Richard Redpath -IBM Software Solutions Division and

Jeff Eisen, Lotus Development Corporation

Date: 8/2/96, Version: Draft 1.0

J-Empower

Java holds the promise of caffeinating the Web, supercharging it with interactive games and animation and thousands of application programs nobody's even dreamed of.

To date, Java software developers have been busy shaping Java into applications that add new life to Web browsers like Netscape and Mosaic, producing programs that combine real-time interactively with multimedia features that have been available only on CD-ROM.

But... Web browsers need not be the only application that reap the benefits of Java. Introducing J-Empower! J-Empower allows you to enable your application to work side by side with Java, linking your application to the cyber-based world of Java applications.

The J-Empower Utility

J-Empower is a developer's tool that provides a simple interface which allows you to embed Java applets into your application. Up until now only Web browsers have been reaping the benefits of the thousands of Java applications available on the Internet. But why stop here? Word Processors, Spread Sheets, e-mail, Lotus Notes, Help Systems, etc... can all benefit from the function of embedded Java applications.

J-Empower takes the form of a system specific DLL and a collection of Java .class files. J-Empower provides a simple 'C' interface which includes functions to interact with the Java runtime and execute and manipulate Java applets within your own application.

J-Empower was built as a result of a practical need to connect Java to real world applications. Specifically, applications like Lotus Note, Lotus SmartSuite, OS/2 Web Explorer and the OS/2 desktop. As a result of working with an initial clientele, J-Empower deals particularly well with applets. However, we are starting to see an increasing demand to go beyond applets. In particular, using J-Empower as a server based tool. In this case, J-Empower will be used to bridge the connection between an HTTP server and "Java CGI" programs. In short, J-Empower is still evolving. However, it's here today and continues to provide a useful service to IBM/Lotus applications that require connection to Java.

A Quick Example

The best way to understand the "caffeinating" process of J-Empower is to examine a simple example.

The following example steps through the creation of a simple Windows95 program with the Tumbling Duke Java applet embedded in the programs client window. The program is written in C, but one could imagine easily adapting the same example to use C++. While "walking" through the following example the sections pertinent to J-Empower will be explicitly highlighted. Appendix A contains the complete program listing.

We start with WinMain. WinMain has the honor of kicking off all the typical things needed to correctly start a Windows95 application. These responsibilities include initializing window data, registering the window class, creating the main window and loading the window accelerators. All these tasks are accomplished by using the helper functions InitApplication() and InitInstance() and the WinAPI LoadAccelerator(). So far nothing out of the ordinary. It's all straight Windows95. Now we introduce our first J-Empower API. jeInitJavaRuntime() is the API that "gets it all started". It is responsible for loading and initializing the virtual machine (runtime). It also sets up the J-Empower service provider which is needed to process requests generated by the other J-Empower API's. jeInitJavaRuntime() accepts two parameters which allows options to be passed into the Java runtime, however; this simple example doesn't require any parameters. The next J-Empower API to get called into service is jeRegisterShowConsole(). This API registers a function that will be passed all Java virtual machine console output message strings. This particular example passes in the helper function MyShowConsole(). As you will see, our implementation of MyShowConsole isn't very ambitious, if fact, we don't do anything within this function. So, feel free to use it as a basis for something more interesting in your own application. Lastly, WinMain enters the mandatory message dispatch loop. Next stop, Window Proc.

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
      MSG msg;
      HANDLE hAccelTable;

	// Perform instance initialization (if not already initialized)
	// This includes initializing window data and registering windows
	if (!hPrevInstance) {
            if (!InitApplication(hInstance)) {
            	return (FALSE); 	// can’t initialize application
            } /* end-if */
      } /* end-if */

	// Perform application initialization
	// This includes creating the main window
      if (!InitInstance(hInstance, nCmdShow)) {
		return (FALSE); 	// can’t initialize instant
      }

	// Activate menu and keyboard accelerators for main window
      hAccelTable = LoadAccelerators (hInstance, szAppName);

	// Start the Java Runtime...
      jeInitJavaRuntime( 0, 0);			

	// Register a function to accept output messages from the Java
	// virtual machine (runtime).
      jeRegisterShowConsole(MyShowConsole);	

      // Main message loop:
      while (GetMessage(&msg, NULL, 0, 0)) {
          if (!TranslateAccelerator (msg.hwnd, hAccelTable, &msg)) {
               TranslateMessage(&msg);
                DispatchMessage(&msg);
          } /* end-if */
      } /* end-while */

      return (msg.wParam);

      lpCmdLine; // This will prevent 'unused formal parameter' warnings
}

All the remaining "action" in our test program occurs in the Window procedure. The following WinProc() fragment illustrates many of the Applet related API's found in J-Empower. Some API's are self explanatory. For example, we process the ID_SHOWCONSOLE command message by issuing the J-Empower API jeConsoleShow(TRUE). The most interesting fragment, from the example below, is the processing of the ID_INITAPPLET command message. It is within this "case" that the Tumbling Duke applet is created. The J-Empower API used to create the applet is jeAppletInit(). This API takes several parameters all of which correspond to the parameters needed to create the APPLET HTML tag. The trickiest parameter is the argument list parameter. However, after looking at the example below, the organization of this parameter becomes quite obvious. One thing to remember is the applet is initially created hidden. To show, the applet you must first obtain the applets container window handle. jeAppletInit() returns an applet handle which can be used to obtain the applet container window. (See Architecture for a more complete explanation applet window relationships).

jeHWNDfromHandle() is the J-Empower API used to obtain the applet container window from the applet handle.

Again, the example almost speaks for itself.

RESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  static JEAPPLETHND hApplet=0;	// applet handle returned by jeAppletInit()
  HWND hwndApplet=0;		// applet container window
  static POINT pt = {0,0};		// applet position
  int wmId, wmEvent;
  PAINTSTRUCT ps;
  HDC hdc;

  switch (message) {
    case WM_COMMAND:
      wmId    = LOWORD(wParam); // Remember, these are...
      wmEvent = HIWORD(wParam); // ...different for Win32!

      //Parse the menu selections:
      switch (wmId) {
          case ID_SHOWCONSOLE:
            jeConsoleShow(TRUE);
            break;
          case ID_HIDECONSOLE:
            jeConsoleShow(FALSE);
            break;
          case ID_INITAPPLET:
            {
              char *argv[5];		// holds the 4 applet parameters
              long height, width;	// applet height and width
              height = 150;
              width  = 150;

              argv[0] = "maxwidth=120";	// set the applet parameters
              argv[1] = "nimgs=16";
              argv[2] = "offset=-57";
              argv[3] = "img=images/tumble";
              hApplet = jeAppletInit(hwnd, "file:////java/demo/TumblingDuke/", null
                                      "TumbleItem",
                                      width, height, 4, argv);
		 // get the applet container window from the applet handle			
              hwndApplet = jeHWNDFromHandle(hApplet);
		 // set the applet window position
              SetWindowPos(hwndApplet, HWND_TOP, pt.x, pt.y,0,0, SWP_NOSIZE);
              pt.y += height + 10;
		 // show the applet container window
              ShowWindow(hwndApplet, TRUE);
		 // now... start duke tumbling	
	       jeAppletStart(hApplet);
            } break;
          case ID_DESTROYAPPLET:
            jeAppletDestroy(hApplet);
            break;
          case ID_EXIT:
            PostQuitMessage(0);
            break;
          default:
            return DefWindowProc( hwnd, message, wParam, lParam );
        } /* endswitch */
}

The J-Empower API

The J-Empower API is broken up into 3 categories: Java Environment, Applets, and Methods. The Java Environment set of API's deal with the Java Runtime. They include functions to start the Java runtime as well as deal with messages generated by the runtime. The API set also allows you to read and write information (properties) to an area common to all Java classes. The Applet API set deals, of course, with either single or sets of applets. The Method API set allows you to call methods in Java classes directly from your C program.

Note: We've considered providing an interface for C++ developers. The problem here is C++ bindings are compiler dependent where C bindings work on any platform/compiler. This fact makes it more difficult to obtain the platform breath needed in J-Empower from C++. So, for now, we'll stick to C bindings.

Java Environment

jeInitJavaRuntime starts the Java runtime
jeVersion return version of JEmpower
jeConsoleShow Show or hide the Java output console window
jeRegisterShowConsole register a function that will be passed all console output
jeGetProperty query a the value of a given property
jeSetProperty set the value of a given property

Applets

jeAppletInit initializes the applet specified
jeAppletStart starts an Applet that has been stopped or initialized
jeAppletStop stops a running applet
jeAppletDestroy destroy an existing applet
jeAppletResize change an applet's dimensions
jeAppletsIconify Notify all applets that your application has been minimized
jeAppletsUniconify Notify all applets that your application has been restored
jeAppletsDestroy Destroy all applets
jeHWNDFromHandle return the window handle given a applet handle
jeRegisterShowDocument register a function that will follow a URL link
jeRegisterShowStatus register a function that will be passed all status information
jeRegisterCheckSecurity register a function that will determine the security features allowed

Methods

jeInvokeStaticMethod call a Java method
jeInvokeDynamicMethod call a Java method associated with the specified object

Architecture

Sun's current framework for Java Applets is constantly changing. As of JDK 1.0.2, there is still no official definition of how "native" applications interoperate with Java. Allowing "native" applications to load, and embed applets is the cornerstone of the bigger "inter-operation" picture. By enabling Java applets, most of the questions and problems with interoperability will be exposed and hopefully solved. "Embedded Java" is the essence of J-Empower. The J-Empower API provides a mechanism for establishing communication with the Java virtual machine (runtime) and interacting with it. The first release of J-Empower focuses on embedding applets in native applications laying the groundwork needed for tight inter-operation between native applications and Java objects.

The Package

J-Empower is packaged as a DLL, containing a little over a dozen C-API's and a ZIP file, containing the Java support classes. Because of the portable spirit of Java, it is critical the the JEMPOWER.DLL be portable.

As you will see in the sections to follow, many of the design decisions made for J-Empower were heavily influenced by portability.

Figure 1 shows the flow of control between "your" application, J-Empower, the Java runtime and an embedded Java applet. In the standard case, your application starts the embedding process by calling one of the entry points in JEmpower.DLL The first API called is usually jeInitJavaRuntime(...). This API establishes the base communication with Java. It does this by loading the Java virtual machine (runtime). This is done by calling an entry point in JAVAI.DLL. This DLL is provided by Sun Microsystems as part of the core Java package. When J-Empower starts the Java runtime, it specifies the name of a Java program which acts as the J-Empower service provider. The name of the J-Empower service provider class is JEMPOWER and is found in the Jempower.ZIP file. The mission of the J-Empower class is to service request like "start applet", "resize applet" and "dispatch method".

Communication paradigm

Figure 2 illustrates the communication paradigm used by J-Empower. The first consideration, when looking at the J-Empower communication paradigm, is the communication boundary. The Java runtime must be able to be created both within a process (thread) as well as in another process. This design requirement is mostly driven by cross platform portability. Our initial attempt used window messages to converse between native code and Java when in process. We now have a limited marshalling/demarshalling routine to support out of process communication. With Sun's introduction of RMI, one could see us using CORBA IIOP to perform the marshalling/demarshalling. This, of course, is a problem if you do not have a CORBA ORB available since you wouldn't want to implement IIOP.

The communication between native code and Java must be both bi-directional and unidirectional with a starting point from either side. This is to allow support for asynchronous callbacks as well as basic notifications.

The communication paradigm is designed to support method invocation. This allows your native application to call any method in a Java class. The is a very powerful feature of J-Empower. An important aspect of method invocation is the automatic conversion of "basic types", e.g., if the method invoked requires a java.lang.Integer, and a long is passed, the long is converted to a java.lang.Integer prior to invocation. The reason why this is vital is because there is no way for native applications to create Java objects outside of the Java runtime.

Applets

The J-Empower API has a complete set of functions dealing with Applet. The difficulty with Applet support is that both Sun and Netscape have different implementations of the Java applet classes. This fact is a good example of the need for a set of API's to control applet embedding in a consistent fashion.

The J-Empower implementation of applets place an applet within a java.awt.Window. Sun uses a panel, and Netscape uses a modified java.awt.Frame. The Window was chosen for two very good reasons: (1) a Window has no parent, so all processing of Java events "stop here" and should not affect "anybody" else, (2) a Window doesn't have a border. As figure 3 illustrates. this Window is then placed within a native window which we call an Applet Container.

An important feature of the J-Empower Applet API's is to have notification of completion. Since all applet actions are asynchronous, there needs to also be asynchronous notification back to the native applications.

Currently, if an applet requests to be resized, the applet is given this new size. If we embed applets into native applications, the "automagic" resizing effect could have bad implications. Our implementation, allows the applet to resize, but the container window will not resize. If the native application requests a resize, both the container window and the applet are resized.

The current framework for applet support assumes that applets are grouped together in a single pool. We have introduced the notion of a context id which allows the programmer to group applets into an AppletGroup which are identified by the context id. Applets are restricted to communicating with only those applets that are (a) in their AppletGroup and (b) cleared for communication by the SecurityManager rules.

Default Applet Security and callback functions

As the J-Empower architecture evolved there seemed to be a growing need for native applications to take a larger part in the Java applet execution. These areas include security, status information, and native application support of http/socket calls.

The J-Empower security model allows the application to give input on any of the 19 possible security checks listed in the table below. All but one are part of the java.lang.SecurityManager. (Item 16 is one that we added.) The following table defines the 19 security checks as well as default behaviors.

Security check Default behavior
1 classloader creation fail
2 thread access fail
3 threadgroup access fail
4 system command execution fail
5 exit VM fail
6 linked library existance fail
7 System.properties() access fail
8 property access if property, a, is requested and property, a.applet is true, then success else fail
9 file read access - if file starts with directories in acl.read/acl.read.default or same directory as the applet then success else fail
10 file write access if file starts with directories in acl.write/acl.write.default then success else fail
11 file descriptor read access success if through Socket or invalid fd otherwise fail
12 file descriptor write access success if through Socket or invalid fd otherwise fail
13 listen fail
14 accept fail

15 connect based on the network mode (appletviewer.security.mode), one of three cases occur:

NETWORK_UNRESTRICTED default = success

NETWORK_NONE:default = fail

NETWORK_HOST:default= if hosts match success, else if proxy trusted (trustProxy) success else fail

16 protocol check This is our creation... If an applet requests another applet, getApplet(), or applets,getApplets(), or we are loading an audioclip or image for an applet, we perform this security check. default = if applet used a "secure" protocol, then fail if an unsecure protocol is used. If the security model is identical, then check the connection security (item 15).
17 package access if the package, pkg, is being accessed and the property, package.restrict.access.pkg, is true then fail else succeed.
18 package definition if the package, pkg, is being defined and the property, package.restrict.definition.pkg, is true then fail else succeed
19 setting factories fail

jeRegisterCheckSecurity is used to register a call back function which can modify the default security behavior for Applets. The J-Empower API details section provides a good example of jeRegisterCheckSecurity.

Besides security overiding, J-Empower supports other types of callbacks which provide assist in providing a tight degree of integration between your application and Java applets. Here are the ground rules that are in play when dealing with the registered callback function. We expect callback functions to be invoked from Java back into native code. The native code cannot call back into Java (we believe this is a difficult problem to solve). It would be nice to have a dynamic facility for adding/removing callback capability but requires thought when dealing with cross process communication.

J-Empower API Details

Please refer to the Postscript documentation (JEMPOWER.PS) included in the JEMPW32.ZIP for complete details of the J-Empower API.