Jeff Eisen, Lotus Development Corporation
Date: 8/2/96, Version: Draft 1.0
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.
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.
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()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. The J-Empower Utility
A Quick Example
The best way to understand the "caffeinating" process of J-Empower is to examine a simple example.
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 }
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 */ }
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 |
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.
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".
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.
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.
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
NETWORK_UNRESTRICTED default = success
NETWORK_NONE:default = fail
NETWORK_HOST:default= if hosts match success, else if proxy trusted (trustProxy) success else 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.
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:
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 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.