Java Plug-in have been in active development for almost two years now (three years, if you count JavaBeans Bridge for ActiveX). The main goal for this product is to deploy the latest JDK/JRE into both Internet Explorer and Netscape Navigator, and quite a lot of people are already using it for applet deployment. Because we have to embed the whole JVM inside different browsers, we have done a lot of tricks and hacks to make it to work. Sometimes, we find that people inside Sun are having problem to understand the internal of Java Plug-in when they browse the source codes. Thus, in this page, we documented some of the tricks and hacks that we have done, so it should make people feel better when they browse the code. Notice that this is not a design document or anything like that, and not all the tricks and hacks in Java Plug-in are documented here. Because I have been working primary on the Navigator side, the issues in Netscape Navigator will be more concentrated in this document.
Java Plug-in mainly consists of two major components: Java Plug-in for Internet Explorer (IE) and Java Plug-in for Netscape Navigator (NS). Java Plug-in for IE is written as an ActiveX control, using the COM interfaces defined by Microsoft. Java Plug-in for NS is written as a Netscape Plug-in, using the Netscape Plug-in API. Currently, Java Plug-in for IE only supports Apartment threading model, and Java Plug-in for NS have similar restriction.In other words, the browser is restricted to call into Java Plug-in only from the main thread, and Java Plug-in is restricted to callback to the browser only in the main thread as well.
Java Plug-in for NS is written using the Netscape Plug-in API. One restriction is that everything must be called from the browser thread -- the thread that loads Java Plug-in into memory in NS.
In Java Plug-in, applets may need to callback into the plug-in for various services, e.g. calling showDocument() or showStatus(). In these cases, the callback can be in any arbitary Java thread. In order to use the services in the browser using the Plug-in API on the browser side, all the callback from Java must be marshaled into the browser thread.
The trick that we used in Win32 is windows subclassing. Since all Plug-in will have a window that is created by the browser in the browser thread, the WinProc is guaranteed to run in the the browser thread. Thus, when there is a need to do marshaling between threads, we basically package everything into a user-defined window message and send it to the plug-in window, and the hook in the plug-in window will recognize the user-defined window message and execute the call in the browser thread.
Here is a list of features that requires callback:
- AppletContext.showDocument
- AppletContext.showStatus
- Automatic proxy configuration support
- Cookie support
- File caching support
- HTTPS support
- RSA signed applet support
- netscape.javascript.JSObject support in Navigator 3/4
- netscape.javascript.JSObject support in Navigator 5
Notice that to send window message to the plug-in window, we must somehow get the correct plug-in instance or plug-in window handle. In most cases, it can be figured out. For example, when AppletContext.showDocument() is called, we can always get the correct plug-in window from the AppletContext object, because each applet is associated with a unique AppletContext object. However, in some other cases, it can't be figured out easily. For example, caching is done in the HttpURLConnection handler, and it has no idea which applet is associated with the call. Thus, we implemented a general plug-in instance map that stores all the running plug-in instance in the map. When we can't find an plug-in window to send message, we just grab a plug-in instance from the map and uses its windows for call dispatching.
In Solaris, the JVM is out-of-process, and the plug-in is responsible for marshaling all the call from the JVM across the process boundary back to the browser through IPC. Because the browser and the JVM use different threading libraries, the out-of-process model actually simplifies the threading issues in this case. Also, it also avoid potential system conflicts like signal handling, or Motif library locking. Similar to the Win32 case, the browser will always call into the plugin from the main thread, and the plugin can only callback into the browser through the Plug-in API in the main thread as well.
Java Plug-in MIME type:
Why are there so many MIME types in Java Plug-in? Let's break it down:
For general purpose:
- "application/x-java-applet" -- used for Java applet
- "application/x-java-bean" -- used for JavaBeans
For specific version of Java Plug-in:
- "application/x-java-applet;version=x.y.z"
- "application/x-java-bean;version=x.y.z"
For OJI:
- "application/x-java-vm"
In each new versions of Java Plug-in, we add two new MIME types for that specific version of Java Plug-in. As you may notice, that adds up a lot after we shipped couple versions of Java Plug-in in the past two years. Supporting multiple versions of MIME types also introduces a problem in Java Plug-in for NS. Netscape restricts that all Netscape Plug-in in Win32 must put all the MIME types it supports into the DLL resources. This limitation makes expanding MIME types support in runtime impossible. Also, because of a bug in Netscape Navigator 3.0x in Win95/98, if the MIME types string exceed more than 256 characters, it will crash the browser during startup. Because we have to support more than 12 MIME types, the MIME types string in the plug-in resource will definitely more than 256 characters. To workaround this bug, we break down the Java Plug-in for NS into several DLLs. Each DLL will have identical codes, but different only in the MIME types each DLL support. Thus, we now have three DLLs in the plug-in directory -- NPJava11.dll, NPJava12.dll, and NPJava32.dll, just because we need to work around the problem described above.
javascript: URL:
Netscape Navigator supports a very special type of URL -- javascript. By using the javascript URL, any JavaScript expression can be evaluated using the JavaScript engine inside Navigator. For example, 'javascript: 1+1' would yield '2' as the result. However, the main power of javascript URL is its capability to access the Document Object Model (DOM) inside the browser. For example, calling 'javascript: document.location' would yield the current value of the document.location property in the current page. We have been using this powerful technique to workaround most of the limitations in the Netscape Plug-in API, including
- Document base.
- Auto proxy configuration support.
- Cookie support.
- netscape.javascript.JSObject support in Navigator 3/4.
Notice that javascript URL can only be used in the Plug-in API in Java Plug-in. The JVM itself doesn't recognize javascript URL, so using it in the applet will result in exception.
Document base in Netscape
Navigator:
One of the biggest limitation in the Netscape Plug-in API is the inability to obtain the document base of the Netscape Plug-in, because there is simply no API for doing it. We spent quite some time to hack around this issue, and luckily we came up with two solutions:
- Calling NPP_GetURLNotify with a URL "javascript: document.location", and the document base will be obtained from the DOM and sent back to the plug-in.
- Calling NPP_GetURLNotify with an empty URL "", and the browser will actually open a HTTP connection to the web server that the current page resides, and request a GET with an empty URL "". The tricky thing here is that the web server will actually return the URL of the current document as the result of the HTTP request, and the plug-in can obtain the result through the streaming API.
We tested these two solutions, both worked, and both have advantages and disadvantages. In #1, calling "javascript: document.location" will actually cause the browser default JVM to start, because of the tight integration between the Netscape JVM and the DOM in Navigator 3/4. In #2, it will cause an extra round trip to the web server in order to obtain the URL. However, we finally decided to go with #2 because starting up the Netscape JVM introduced more impacts and side-effects to the plug-in. One side effect of using #2 is that the URL that it returns will contain the path without the document name. In other words, if the document base should be "http://java.sun.com/a/b/c.html", the returned document base will be "http://java.sun.com/a/b/". To minimize the confusion, we updated Java Plug-in for IE, so it will ignore the document name when it needs to deal with document base.
In Navigator 5, this limitation is gone because we have added a new method in nsIPluginTagInfo2::GetDocumentBase() to obtain the full document base, so we no longer need to do this hack.
Cookie support:
Basically, when an applet is downloaded, Java Plug-in will try to download the CLASS/JAR files by making a HttpURLConnection. However, in some web servers, cookies support is needed for authentication or session tracking. As a result, when Java Plug-in makes a HttpURLConnection to the web server, it doesn't send any cookie in the HTTP header, and the HTTP request will fail. When works around this problem in two ways:
- In Java Plug-in for IE, we explicitly uses WinInet API to obtain the cookie. Because Internet Explorer also uses WinInet for making all the network connection, any cookie that is valid in Internet Explorer can be obtained by Java Plug-in using WinInet. Thus, when Java Plug-in makes a HttpURLConnection, it callbacks into native code and obtain the cookie. The cookie obtained from WinInet will always be a valid one, so the correct cookie will always get sent along with the HttpURLConnection in IE.
- In Java Plug-in for NS, this is much tricker. Another limitation of the Netscape Plug-in API is the inability to obtain the cookie of the document, because no such API exists. Thus, we work around it again by using "javascript: document.cookie", and this will return all the valid cookies associated with the document. Notice that it is possible that make a HttpURLConnection to a URL that is totally different from the document base. In this case, returning the cookies assciated with the document will be a security flaw. We workaround this by caching all the plug-in instance in the map. When HttpURLConnection callbacks, Java Plug-in will enumerate all the plug-in instances and ask for their cookies. If any of the plug-in instances have a document base which is the same as the URL of the HttpURLConnection, then the cookie associated with that plug-in instance is sent. Otherwise, no cookie will be sent. To summarize, we try to do the best we can in Navigator to return the cookie, without security flaw. However, we cannot guarantee that the correct cookie will always be returned because we have no access to the cookie store in Navigator 3/4. Notice that this limitation will be gone in Navigator 5 because we have added a new method in nsICookieStorage::GetCookie and nsICookieStorage::SetCookie for manipulating the cookie store.
In some cases, dealing with cookie is still a problem in Java Plug-in. Thus, in Java Plug-in 1.2.2, we allow users to set the cookie explicitly if they know what they are doing. If cookie is set in the HttpURLConnection by the applet, HttpURLConnection will not callbacks into native code. Instead, it will use the cookie that has been set and make a HTTP connection. In this way, the users can override the cookie behavior themselves if they need.
HTTPS support:
Lots of people have been requesting HTTPS support in Java Plug-in, and we finally add such support in Java Plug-in 1.2.2 by using the browser API. However, because of the limitation of the Netscape Plug-in API, we are only able to support two basic HTTP operations: GET and POST.
In Java Plug-in for IE, WinInet is used to implement the HTTPS support in native code. All request headers set by the applet will be sent through HTTPS, and all the respond header will be available for access in the applet.
In Java Plug-in for NS, the Netscape Plug-in API -- NPP_GetURLNotify() and NPP_PostURLNotify() are used to implement the HTTPS support in native code. However, because of the limitation, no request headers set by the applet will be sent through HTTPS, and no respond header will be available for access in the applet.
One other trick we have done in performing HTTPS POST is that we explicitly added the HTTP header "Content-Length" and "Content-Type" in the request. The issue is that for most web server out there, they will not recognize a POST request if these two headers are absent.
In Navigator 5, the limitation in transferring the HTTPS headers should be gone. Netscape is currently working on a new networking library project called Necko, and their engineers have promised that we will have capability to access the header information. The other possible feature is to support the HEAD operation in HTTPS in Navigator 5, if Necko is capable of doing that.
Protocols support and proxy
configuration:
In Java Plug-in, it supports five network protocols: HTTP, FTP, Gopher, SOCKS, and HTTPS. Protocol support for HTTP, FTP, Gopher and SOCKS are built-in into the JDK/JRE. However, the main problem for the protocol support in JDK/JRE is that it assumes static proxy configuration setting. In the JDK/JRE, the protocol handler always obtain the proxy configuration setting from a system property, which is entirely useless in Java Plug-in.
Basically, there are three types of proxy configurations supported in Internet Explorer and Netscape Navigator:
- Direct Connection (No proxy)
- Manual Proxy Configuration
- Automatic Proxy Configuration
Because Java Plug-in runs inside both browser, it must support all three types of proxy configuration. Because all the default protocol handler in JDK/JRE only support static proxy configuration, Java Plug-in overrides all these protocol handlers to support the proxy configuration it needs. When the protocol is used by an applet in Java Plug-in, the protocol handlers will callbacks into Java Plug-in to obtain proxy configuration information. Supporting #1 is easy because no proxy is needed. Supporting #2 is a bit tricky because we must support proxy override list. Thus, when a connection is made, we must compare the URL with the proxy override list to determine the final proxy configuration information. Supporting #3 is the trickiest one, because the proxy configuration is encapsulated in a JavaScript function called FindProxyForURL() that is written by the administator. Whenever proxy information is needed, the JavaScript function must be evalulated against a given URL to yield the proxy information. What makes it worse is the fact that there are about 15 pre-defined JavaScript functions that FindProxyForURL() can call. The hack we used is as follows: Implemented these 15 pre-defined functions in pure JavaScript, and emulate their behaviors as much as we can. Whenever there is a callbacks for proxy information, we append the FindProxyForURL() with our pre-defined functions, and send it to the JavaScript engine for evaluation. When the result comes back, we simply return the result back to the protocol handlers. How do we access the JavaScript engine?
- In Java Plug-in for IE, we access the JavaScript engine by using the JavaScript engine COM objects that shipped with IE.
- In Java Plug-in for NS, again, this is a limitation in the Plug-in API. Thus, we workaround it by using javascript: URL trick again. Yes, we actually convert the FindProxyForURL() and all the pre-defined JavaScript methods into a single javascript: URL, and send it to the browser through NPP_GetURLNotify.
By default, HTTPS is not supported by JDK/JRE, so we implemented the HTTPS protocol handlers so it will call back into the plug-in native code to use the browser API.
One other interesting note is that you won't find a protocol handlers for SOCKS. Why? Because SOCKS is just a protocol for opening up the firewall. Once the firewall is opened up, the communication is still done by HTTP, FTP, Gopher or HTTPS. Thus, the key to SOCKS support is actually in the socket level. When HTTP is used for communication and if SOCKS is enabled, special handshakes will be performed at the socket level, before the HTTP connection is established.
All the Java Plug-in protocol handlers are located in sun.plugin.protocol package.
File Caching, JAR Caching and
Applet Caching:
There have been lots of confusion over file caching, JAR caching, and Applet caching features in Java Plug-in. Let's clear them up!!
File Caching is a feature in Java Plug-in 1.2. Its main purpose is to store all the CLASS/JAR files that the applet used into the browser cache. Thus, when the file is requested the second time by the applet, the file should not be downloaded again.
JAR Caching is also a feature in Java Plug-in. Its name is a little bit misleading. The main purpose is to cache the applet's classloader in memory inside Java Plug-in, even there is no external reference to the classloader or if the applet is already destroyed.
Applet Caching is a new feature in Java Plug-in 1.3, and its main purpose is for fine-grain caching control over JAR files, and flexible repository support. Its name is misleding as well, and "Applet Installation" or "Persistance Applet support" will be more appropiate. Please check
To support file caching, HttpURLConnection is overriden thus that it can intercept all the HTTP request. Whenever the requested is a CLASS/JAR files from the web server, Java Plug-in will intercept it and callback into native code. In Java Plug-in for IE, Win32 URL moniker is used to download the files into the browser cache, and returns the cached file back to the HttpURLConnection, so the file content can be read as stream. In Java Plug-in for NS, Netscape Plug-in API is used for downloading the file into the browser cache. The tricky thing here is that there is no known way to do it in Navigator, because of the limitation of the Netscape Plug-in API. We workaround it by calling NPP_GetURLNotify() and ask the browser to save the HTTP result as a file. The side effect is that the file will actually be stored in the browser cache. Thus, if the URL is for a CLASS/JAR file, the HTTP result will be the file itself, and storing the result as file will effectively make the CLASS/JAR file to store in the browser cache. Notice that we still have no way to enumerate or manipulate the cache entries in Navigator.
RSA signed applet support:
RSA signed applet support is a feature in Java Plug-in 1.2.2, and it is restricted to JAR file only. RSA certificate is supported by using a RSA security provider, provided by our security team. When a RSA signed applet is loaded, the security provider will be in effect to extract all the certificates associated with the applet JAR file, and store them into the CodeSource object. We also override the getPermissions() method in the plug-in classloader. When the applet is loaded, the getPermissions() in the classloader will be called, and we have a chance to return the right permissions by verifying the certificate chains in the CodeSource object.
Verifying the certificate chains is easy: Start from the first certificate in the certificate chain. Make sure the signature of certificate 'i' can be verified using public key from certificate 'i+1'. This process continue until certificate 1 to i are verified. The remaining thing is to verify the last certificate in the certificate chain. Normally, the last certificate is a self-signed certificate issued by the certificate authority, so we need to verify to see if this certificate authority is valid.
In IE, Microsoft Crypto API 2.0 is available for manipulating certificate and managing certificate store. Thus, we decided to use the root CA store in IE to verify against the certificate authority in the RSA signed applet we have in Java. Crypto API is used to enumerate each certificate in the root CA store to see if the certificate authority in the certificate chain is valid. If none of them match, this cerificate authority in the JAR file certificate chain cannot be verified, so we treat the applet as untrusted automatically. However, if any one of the certificates in the root CA store matches with the CA in the JAR file certificate chain, then it only means one thing: the JAR file is signed properly by a recognized root CA. It doesn't mean that it can be trusted though.
To determine if the applet can be trusted, we popup a security dialog to give the user three options: Deny, Grant this session, Grant Always. If the user selects Deny, the applet will be treated as untrusted. If the user selects Grant this session, the certificate in the JAR file will be stored in a memory cache, so any applet signed using the same certificate chains will be trusted for the entire browser session. If user selects Grant Always, the certificate in the JAR file will be stored in a persist cert store called "Plugin" using the Crypto API. Thus, any applet signed using the same certificate chains will be trusted forever. Notice that this decision can be reversed from removing the certificate from the Java Plug-in Control Panel.
In the current implementation, we also verify the certificate effective and expire date as well. Thus, if your certificate expires already and you use it to sign the JAR file, the JAR file will be loaded as untrusted.
Notice that Netscape doesn't provide any API in Navigator 3/4 to access their root CA store. Thus, to use RSA signed applet in Java Plug-in in Navigator, you will need to have IE installed. This is a pain, but we have no choice.
Also, for some reasons, enumerating the root CA store in IE3 will yield nothing. In other words, we cannot access any root CA certificate in IE3. Thus, to use RSA signed applet in IE, you must have IE4 or later.
In general, using RSA signed applet is very easy in Java Plug-in. It is the requirement of IE4 that confuses the users. In the future, we can resolve this problem if the JDK/JRE bundles its own root CA store, so we don't have to rely on IE anymore. Also, it will work on Solaris as well.
In Navigator 5, Netscape will expose the root CA store through the nsICapsManager interface in Mozilla, so we should be able to use it to verify the certificate chains in the JAR file in both Win32 and Solaris.
netscape.javascript.JSObject in IE
and Navigator 3/4:
netscape.javascript.JSObject is a special Java class that allows Java applet to access the document object model of the current page. It is supported in both NS and IE default JVM. Java Plug-in supports JSObject in both IE and NS as well, but the implementation is quite different.
In Java Plug-in for IE, the entire document object model can be accessed through COM using IDispatch. Thus, whenever JSObject.getWindow get called, the IDispatch associated with the native Window object in the DOM will be returned, and all the calls in JSObject will just delegated to IDispatch in the native code.
In Java Plug-in for NS, again, there is no Netscape Plug-in API to do it, so our solution is to use our mighty javascript: URL hack through the Netscape Plug-in API. The idea is that we can access information about the JavaScript document object model using the "javascript:" URL. To emulate the JSObject model inside the plugin, a technique called lazy/late evaluation is used. For example, when the following code is running:
JSObject window = (JSObject) JSObject.getWindow(this);
JSObject document = (JSObject) window.getMember("document");
JSObject location = (JSObject) document.getMember("location");
Object host = location.getMember("host");The above code is used to access the "window.document.location.host" property in the browser window. In each line in the above code, a seperate evaluation context is created in each object. Since we know exactly when the document object model looks like, we also know when we should defer the evaluation and when we should execute the evaluation. Thus, when "host" is accessed from the Location object, we know it is the leaf of the document object model, and we execute the evaluation. Using the technique, we can basically access any method/property in the predefined document object model.
Currently, the following objects are supported: Navigator, Window, Document, Location, Form, Element, Link, History, Frame, Anchor, URL, Option and Array. We provide basic support for Navigator 3 document object model. Thus, by accessing NS3-defined methods/properties in the above objects should be successful. Since we only support Navigator 3 document object model, Java Plug-in running applets inside Navigator 4 can only access the Navigator 3 document object model at this point. Thus, to access the DHTML or other features in Navigator 4, the above method will not work. However, there is a special method in JSObject called eval, and we basically pass the eval expression directly to the browser for evaluation. Thus, people can still access DHTML or other stuffs that are not supported directly from the JSObject getMember/setMember/call functions.
To access custom property/method in the HTML page, there are currently two ways available:
- Use JSObject.eval(expr). This will execute the expression in the current window context.
- Use the Window JSObject and do setMember/getMember/call. If the property is available or the function is callable, it will execute it and return the result. However, if the property does not exist, or the function does not have return value, null will be returned.
Anyway, we have done quite a bit testing in the JSObject support in Navigator 3/4, and it works pretty well. The only limitation is that this is implemented through emulation, so it may not work in Navigator in some boundary cases of using JSObject.
Notice that this hack will go away in Navigator 5, as OJI provides basic Java to JavaScript bi-directional communication through LiveConnect.
Scripting in Navigator 3/4:
We have been telling our customers that scripting is not possible in Navigator 3/4 with Java Plug-in. Actually, this statement is not entirely true. In Navigator 3/4, plug-in can be scripted if it provides a Java wrapper class. Thus, if Navigator needs to script the plug-in, it will load the Java wrapper class and invoke its method in Netscape JVM, and the Java wrapper class will callback into the plug-in through JRI (not JNI) that Netscape supports. So it sounds possible, but there are several limitations:
- Navigator only obtains the Java wrapper class once for the lifetime of the plug-in, because it assumes that the Java wrapper class should not be changed between different plug-in instances. This is true for most of the Netscape Plug-ins out there, but this is not true in Java Plug-in. Because each Java Plug-in instance can host a different Java applet, it needs to supply a different Java wrapper class for each plug-in instance.
- Using this approach will start the Netscape JVM, which increases the memory footprint quite a lot.
Anyway, the hack that we came up with is as follow: create a Java wrapper class that contains methods like setField, getField, call, etc, and this wrapper class is used for all Java applets inside Java Plug-in. For example, to call a method in an applet in Java Plug-in, you can do the following:
<APPLET code=myClass NAME=a WIDTH=100 HEIGHT=100> </APPLET><SCRIPT language="JavaScript"> var param = { 0, "Hi", null }; document.a.call("method1", param); </SCRIPT>When the plug-in is actually called through the Java wrapper through JRI, it will unpackage the parameters and use Java Reflection on the actual applet to make the call. Thus, all the call and field access to the Java applet will be done indirectly by setField, getField, call, etc in the wrapper class. We have tested it, and it actually works reasonablely. However, because this hack requires all the HTML writer to use a new style to call the applet method in Java Plug-in, we thought that it would introduce lots of confusion to users, and we decided to back out this hack. That's why you don't see it in Java Plug-in today.
Notice that OJI will provide bi-directional JavaScript and Java communication support, so scripting will work again in Navigator 5.
Automatic Installation in Java
Plug-in for IE:
Java Plug-in for IE installation is fully automatic, and Microsoft packaging and code signing techologies are used for creating this installation. Basically, the installation contains three parts:
- OBJECT tag
- CAB file
- INI and actual Java Plug-in Installer.
In the HTML page, Java Plug-in is specified using the OBJECT tag. For example,
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" WIDTH=455 HEIGHT=543 codebase="http://java.sun.com/products/plugin/jinstall.cab#Version=1,3,0,0"> <PARAM NAME = CODE VALUE = "crossword.class" > <PARAM NAME="type" VALUE="application/x-java-applet;version=1.1"> <COMMENT>The classid is used by IE to launch Java Plug-in. Here is how it works: When IE encounters this tag, it will do the following:
- Locate the classid in the registry "HKEY_LOCAL_MACHINE\Software\Microsoft\Code Store DataBase\Distribution Units\<classid>".
- If the classid does't exist in the registry key, download the CAB file from the CODEBASE of the OBJECT tag.
- If the classid exists, compare the "InstalledVersion" subkey value in "HKEY_LOCAL_MACHINE\Software\Microsoft\Code Store DataBase\Distribution Units\<classid>\InstalledVersion" with the version number specified in the CODEBASE in the OBJECT tag.
- If the installed version is higher than the one in the tag, launch Java Plug-in immediately. Otherwise, download the CAB file from the CODEBASE of the OBJECT tag.
CAB file is a Microsoft standard way of packaging other files, similar to JAR file in Java. In Java Plug-in, the CAB file contains two files: The INF file and the JINSTALL.EXE file. In Windows, INF is the installation script which describe all the components and files that will be installed. Unfortunately, when an INF file is used in a CAB file, it has lots of restrictions and most of the Microsoft documented syntax doesn't work!! JINSTALL.EXE is our mini-application that redirect users to download Java Plug-in from different sites. We defined the CAB file as follow:
; Version number and signature of INF file.
;
[version]
signature="$CHICAGO$"
AdvancedINF=2.0
; The order of files in this section defines the download order.
; Last in First download.
[Add.Code]
jinstall.exe
beans.ocx=beans.ocx
; beans.ocx is the OCX name of the bridge. It is included in bridgeinstaller, so
; the bridge runtime has to be download.
;
[beans.ocx]
FileVersion=#PLUGIN_VERSION#
RegisterServer=no
clsid={8AD9C840-044E-11D1-B3E9-00805F499D93}
hook=bridgeinstaller
[jinstall.exe]
file-win32-x86=thiscab
FileVersion=#PLUGIN_VERSION#
; RegisterServer=yes
; jinstall.exe will be executed.
;
[bridgeinstaller]
run=%EXTRACT_DIR%\jinstall.exe #HTTP_SERVER#/jinstall_#PLUGIN_VERSION_FOR_FILE#.ini
The key thing in the INF file is the clsid and hook in the [beans.ocx]. When IE downloads the CAB file, it will try to obtain the INF file in order to install the component specified in the OBJECT tag classid. Thus, the clsid in the [beans.ocx] section MUST match the classid in the OBJECT tag, or it will not work. Once IE finds the clsid in the INF file, it will try to install it, and this will trigger the hook in the [beans.ocx], and the run in [bridgeinstaller] will be executed. JINSTALL.EXE is specified in the run in [bridgeinstaller], so it will be executed from the CAB file.
The main purpose of JINSTALL.EXE is to obtain a list of possible download location and present it to the user, so the user can pick and choose where they want to download Java Plug-in. The list of download location is stored in an Windows's INI file, that is downloaded from java.sun.com from JINSTALL.EXE.
Once the user pick the location, JINSTALL.EXE will download the Java Plug-in installer from the right location and launch the installer. After the installation is done, JINSTALL.EXE will exist, and IE will launch Java Plug-in accordingly.
SmartUpdate support:
SmartUpdate is a way for Java Plug-in automatic installation in Navigator 4 or later, similar to what Java Plug-in auto installation does in IE. There are multiple ways to use SmartUpdate, but not all of them are good or reasonable. Here is the way we suggest to use SmartUpdate for Java Plug-in: in every converted HTML page, specify
<SCRIPT language="JavaScript" src=trigger.js> </SCRIPT>at the beginning of the page. This will make Navigator to read in the SmartUpdate trigger script and start the SmartUpdate installation if needed. Unfortunately, this tag only needed to specified once per page, so we cannot use the HTML Converter to automatically add it, unless of course we modify the conversion engine.
Also, nobody except me have tested the SmartUpdate support, so we still don't know how well it works externally. As this document is written, we haven't shipped the SmartUpdate support to any of our customers, so it still remains to be seen whether it will be shipped at all.
Swing focus bug:
This is probably one of the most nasty bugs in Java Plug-in. We have fixed this couple of times. However, whenever the AWT implemention is updated, it will break Java Plug-in one way or the other. We have to use various hacks to workaround it, but the worst thing is that we don't know why it breaks, and why the hack works. So fixing Swing focus bug is more like trial-and-error. Anyway, there are still few tips we can share here:
- Make sure all mouse and focus related Windows message is filtered from the container -- the browser in our cases. Once I was notifying the browser that my component had the focus, but the browser actually stole the focus from my component whenever it saw WM_SETFOCUS and WM_KILLFOCUS, so my component never gained the focus, and I fixed this by window event filtering.
- Make sure you don't call back and forth between the embedded frame and the native container window in focus/mouse related events, or the browser may deadlock.
- Avoid manipulate any Java lightweight component using Windows handle in native code. Because the component is lightweight, using Win32 API to manipulate it will yield undeterministic result.
- Always test your solution with minimizing, maximizing and resizing the window, your solution may break in these cases.
- Always test your solution in all versions of browsers. Different versions of Navigator or IE may behave differently.
- Be patient, try several times, and good luck!!
Java Plug-in HTML Converter:
Most of the details have been documented in the HTML Converter README file, so they won't be repeated here. However, one interesting misconception is that people can only use the templates that we provide in the converter, and this is not true at all. The HTML Converter convertion logic is separated from the file generation logic, and that's why templates are needed. Users are free to modify and uses their own templates if they want. The four predefined templates in the HTML Converter are just happened to be those most people need.
New COM objects in Java Plug-in
1.3:
In Java Plug-in, a lot of common codes have been modulized into different COM objects for code reuse purpose. These COM objects reside in BEANS.OCX, JPISHARE.DLL and JPINS32.DLL.
In BEANS.OCX, it mainly contains the code for Java Plug-in for IE, and the COM object for JavaBeans Bridge for ActiveX. JavaBeans Bridge for ActiveX enables any JavaBeans to run in native Win32 application as an ActiveX control.
In JPISHARE.DLL, it contains three separate COM objects: JavaVMService, CryptoService and ShellService. JavaVMService currently is used for starting the JVM. CryptoService is used for certificate verification of RSA signed applet. ShellService is used provide Task icon when the console is opened, currently it is not implemented.
In JPINS32.DLL, it contains two COM objects: BackwardAdapter and OJIPlugin. BackwardAdapter is the essential OJI backward adapter for running the OJI plug-in in Navigator 3/4. OJIPlugin is the actual Win32 OJI plug-in for Netscape Navigator.
Compiler and Linker flags in Java
Plug-in build:
The build process in the Java Plug-in 1.3 workspace have been completely updated. All the major compiler and linker settings are now stored in /build/win32/config. The compiler and linker flags we decided to use are actually quite similar to JDK/JRE 1.3.
Compiler:
- /MTd in Debug mode, /MD in Release mode -- these flags are used for linking the C runtime library. In Debug mode, all the binaries will be statically linked with LIBCMD.LIB, so no extra DLL needs to be distributed when debugging on other machine. In Release mode, all the binaries will be linked with MSVCRT.LIB, so all DLL can share the MSVCRT.DLL that comes with JDK/JRE, and the resulting binary sizes should be smaller.
- /W3 -- set the warning level to 3. Notice that /W4 cannot be used because the build will fail when compiling the OJI plug-in using the Netscape header files. No, this is not our fault, but we have to live with it.
- /Od in Debug mode, /O1 in Release mode -- for Debug mode, turn off optimization. For Release mode, space optimization is used. Notice that Microsoft is also using /O1 in their shipping products.
- /GX -- enable C++ exception handling.
- /GZ in Debug mode -- enable runtime debug checks.
- /Zi -- Enable debugging information for both Debug and Release mode. This is the key for debugging in Release mode products.
- /ZI in Debug mode -- enable Edit and Continue Debug Info in Visual C++ 6.0.
- /D "_ATL_STATIC_REGISTRY" in Release mode -- make sure we don't depend on ATL.DLL in Release build, if ATL is used.
Linker:
- /subsystem:windows -- make sure the resulting binary is for the Windows subsystem.
- /incremental:yes in Debug mode, /incremental:no in Release mode -- make sure incremental linking is not used in Release build. Otherwise, the binary will be bigger because of extra padding in the PE file.
- /debug -- linked with Debug information in the OBJ and LIB files.
- /pdbtype:sept -- make sure the Debug information will be stored in a separate PDB (Program Database) files, instead of linking into the resulting EXE/DLL files.
- /map:XXX -- generate MAP files.
- /opt:ref in Release mode -- instruct the linker to link only the functions that have been referenced into the resulting binary. This is to eliminate dead code in the Release build.
We have reduced the Java Plug-in binary sizes quite a bit in 1.3 by combining the compiler and linker flags above.
Also, we have enhanced the Java Plug-in Release build, so it is also built with PDB file for Debug info, and MAP file for listing method addresses in the DLLs. This should make debugging in Java Plug-in much easier.
The other related issue is REBASE DLL in Java Plug-in. As a matter of fact, JDK/JRE will rebase all the plug-in DLL when creating the installer from the JDK workspaces, so we don't have to do it ourselves. However, if you are building the JRE installer from Java Plug-in workspaces, no REBASE will be done, so you should expect the loading will be much slower because of the work involves in DLLs relocation and address fixup.
How to build Java Plug-in:
To build Java Plug-in, you will need couple things:
- Microsoft Visual C++ 5.0 SP3 or 6.0 SP2
- MKS Toolkit 6.x
- Microsoft Windows NT 4.0 Service Pack 3 SDK
- Microsoft Internet Client SDK 4.0 or later
- Java SSL standard extension.
Once these tools are installed, please set the following environment variables:
- set ALT_BOOTDIR=<jdk1.2.2 directory>
- set ALT_BOOTDIR_11=<jdk1.1.8 directory>
- set ALT_BOOTDIR_12=<jdk1.2.2 directory>
- set SP3SDK=<Windows NT 4.0 Service Pack 3 SDK directory>
- set INETSDK=<Internet Client SDK directory>
- set SSL=<Java SSL extension directory>
- set PATH=<MKS Toolkit directory>;%PATH%
Once the environment is set correctly, run the vcvars32.bat from Visual C++ to setup the build environment.
To actually build Java Plug-in, do the following:
cd build/win32
nmake allThis will build Java Plug-in in Release mode. To build Java Plug-in in Debug mode, do the following:
cd build/win32
nmake all CFG="Debug"To clean up the build, please do the following:
cd build/win32
nmake cleanor
cd build/win32
nmake clean CFG="Debug"Here is a basic layout of the workspace:
\build\win32 -- All makefiles for Win32 build
\build\solaris -- All makefiles for Solaris build
\build\share -- Shared information for build configuration between Win32 and Solaris
\converter -- Java Plug-in HTML Converter
\demo -- JavaBeans Bridge for ActiveX demo, now obselete
\doc -- Java Plug-in documentaion, not often used these days
\java -- All Java codes for supporting Java Plug-in
\jinstall -- Automatic installation for Java Plug-in in IE
\jpishare -- Shared DLL for Java Plug-in for IE and NS in Win32
\ocx -- Java Plug-in for IE
\oji-plugin -- Java Plug-in for NS
\oji-plugin\src\win32 -- Java Plug-in for NS in Win32
\oji-plugin\src\solaris -- Java Plug-in for NS in Solaris
\packager -- Packager DLL used by Java Plug-in for IE for typelib generation and bean packaging.
\share -- Common codes shared by Java Plug-in
\unreg\src\dos -- Unregister utility for JavaBeans Bridge for ActiveX, DOS based
\unreg\src\win32 -- Unregister utility for JavaBeans Bridge for ActiveX, Win32 based.Notice that not all the directories are listed here. Once Java Plug-in is built, the binary can be found in \build\win32\bin and \build\win32\lib.
To build the actual JRE installer with Java Plug-in, do the following:
cd build/win32/ishield
nmake allMake sure you have InstallShield 5.x installed. The resulting binaries can be found in build/win32 after the build.
In general, we kept all the Mozilla/OJI headers that we used in the workspaces /oji-plugin/include. However, there may be chances that you want to build Java Plug-in against the latest Mozilla headers. To do that, please specify
set MOZ_DIST=<Mozilla directory>
before you build.
In some other cases, you may want to only build the Win32 OJI plug-in without building the entire workspace. To do that, please specify
set MOZ_OJI_PLUGIN=1
before you build.
Mozilla buzzwords:
Netscape tends to change their project code name every couple weeks. To avoid confusion, you should understand the following terms, before you try to browse http://www.mozilla.org
- Mozilla -- overall Netscape Navigator Open Source Effort. It is also the code name for the original Netscape Navigator -- it stands for Mosaic Killer.
- Gromit -- original code name for Netscape Navigator 5. It is obselete.
- Raptor/Gecko -- code name for Netscape Next Generation Layout engine, and it is original called Raptor. However, it was later found that some companies have licensed the name, so they switch it to use Gecko.
- SeaMonkey -- latest code name for Netscape Navigator 5.
- Necko -- code name for the new network library project.
- Mocha -- original code name for JavaScript.
- Rhino -- code name for JavaScript in Java project.
- Electric Fire -- code name for Netscape Java Just-In-Time compiler.
- NSPR -- Netscape Portable Runtime. It is the runtime layer that all Netscape projects uses in all platforms.
- Bugzilla -- Mozilla Bug Tracking System.
- Tinderbox -- Tool in Mozilla to determine the state of the tree.
- Bonsai -- Query tool for browing Mozilla source codes online.
- XP* -- Cross Platform. For example, XPCOM -- Cross Platform COM. XPFE -- Cross Platform Front End.
- CVS -- Concurrent Versions System -- version control software used in Mozilla.
Backward Adapter in Open Java
Interface/Open JVM Integration (OJI):
OJI is a set of interfaces based on XP-COM that allows different vendors to plug-in their JVM into Navigator 5 as the default browser JVM. There are several major features:
- APPLET/EMBED/OBJECT tag support
- LiveConnect -- Java and JavaScript bi-directional communication
- RSA signed applet support
- Various browser integration, including cookie, proxy, console, pref dialog, ... etc.
In Java Plug-in 1.2.x and 1.3.x, we have rewritten the entire Java Plug-in to use OJI. However, because OJI is based on XPCOM, and it is completely different than the old Netscape Plug-in API, OJI plug-in will not work in Netscape Navigator 3/4 anymore. However, we solved this problem by using another piece of code called backward adapter -- it mapped all the Netscape Plug-in entry points and APIs into OJI internally. Thus, by linking the backward adapter and the OJI plug-in together, the OJI plug-in will work in all versions of Navigator. Notice that when the OJI plug-in is running in Navigator 3/4, the browser will communicate with the plug-in through the backward adapter, and the plug-in can only behave like a general Netscape Plug-in. Iit doesn't have any of the OJI features listed above. However, when the OJI plug-in is running in Navigator 5, the browser will talk to the plug-in directly through OJI, and it will have all the OJI features.
Java Plug-in for NS have been rewritten to take advantages of the Open Java Interface in Mozilla. Basically, all OJI interfaces are single-threaded. In other words, the OJI plug-in will be called from the main thread, and the plug-in is also restricted to callback to the browser in the main thread only. This is actually quite similar to the threading model used in the Plug-in API in Navigator 3/4. However, there is one big different: in Navigator 3/4, the layout engine is running in the main thread, while the JavaScript engine is running in a separate thread. In Navigator 5, both layout and JavaScript engine are now running in the main thread. This presents quite a challenge because it means that JavaScript engine can block the layout engine easily and freeze the browser UI. Thus, to avoid potential problems in Mozilla, here are what we do:
- Never, ever block the main thread. Even if we must block, implement a dispatch message loop to keep the UI alive.
- For all Java threads callback, always marshal the calls back to the main thread for execution. Similar to the situation in Navigator 3/4, this can be done by windows subclassing to the plug-in window. Netscape also provides a way to use nsIThreadManager to put a callback request to the thread queue of any NSPR thread you want, and the callback method will be executed in corresponding thread. We used the nsIThreadManager for implementing netscape.javascript.JSObject in Mozilla, because it requires a callback to nsILiveConnect in the main thread. Check the LiveConnect section in this document for more details.
Anyway, although Netscape usually claim some of the XPCOM/OJI interfaces can be called from any thread, my advice is: DON'T DO THAT. The browser will always call you in the main thread, and you should always callback the browser from the main thread only.
From the past experience working with Mozilla, more than often, some components in Mozilla sometimes made wrong assumption about how threads are used, and how interfaces are called. These assumptions are wrong mainly because they don't take the JVM callback situation into account when the design was made. In our case, any Java thread may be called back into the plug-in through the native method, and the browser may not know the existance of these threads at all because these threads are created by the JVM. Thus, when these threads callback into a XPCOM/OJI interfaces, the whole things will break if any of the interface implementations require access to the thread local storage. Because nothing is stored in the thread local storage in these Java threads, it will result in error, assertion, or browser crash. Anyway, this is one of the main reasons why you should restrict the XPCOM/OJI call to the main thread.
The threading issue is much more complicated in other platforms. Basically, Netscape uses its threading library NSPR (Netscape Portable Runtime) in all its products to encapsulate the underlying system layer, e.g. threading, synchronization, ... etc. In Win32, it is relatively simple, because all the NSPR primitives are mapped directly to the Win32 primitives. Java Plug-in uses the in-process model, so the browser and the JVM are running inside the same process. On the other hand, things get pretty complicated in MacOS and UNIX. In these platforms, NSPR primitives are not mapped directly to the native primitives in these platforms. For example, in these platforms, NSPR have its own threading library, different than the kernel thread, the POSIX thread or even the green thread library. Because the JVM on these platforms are normally using either the kernel thread, the POSIX thread or the green thread library, it is different than NSPR. Thus, when we try to embed the browser that uses NSPR with the JVM that uses a different threading library, special handling needs to be done when the browser and the JVM communicate through Java Plug-in.
In UNIX, Java Plug-in uses the out-of-process model, and the plug-in is broken down into two pieces. One piece of the plug-in is running inside the browser with NSPR thread and communicate with the browser using OJI. Another piece of the plug-in is actually launching and communicating with the JVM in another process through JNI, using the native/green thread library. In the Solaris case, the plug-in pieces in two processes communicate with each other through IPC. Notice that in this model, the interaction between two different threading systems in the browser and the JVM occur only in the IPC.
In MacOS, the situation is worse. Unlike Win32 or UNIX, MacOS is cooperatively multitasking. When dealing with NSPR and native primitives, the browser and the plug-in must be careful enough to yield or give up the control in the right time; otherwise, the browser or the plug-in may not be responsive. The Mac OJI plug-in is also broken into two pieces. One piece of the plug-in is running with the browser with NSPR thread and communicate with the browser using OJI. Another piece of the plug-in is launching and communicating with the JVM in the same browser process through JNI, using the native/green thread library. These two plug-in pieces in the same process communicate with each other through share memory and constant pooling. The interaction between different threading systems in the browser and the JVM occur only in the share memory.
In Win32, we don't have to worry about it because NSPR is exactly the same as the native thread library that JVM uses.
LiveConnect support in Navigator
5:
LiveConnect enables Java and JavaScript bi-directional communication between Mozilla and Java Plug-in. This is the most complicated feature to design and support in OJI. Java->JavaScript communciation is done by using netscape.javascript.JSObject and nsILiveConnect, and JavaScript->Java is done by using straight JNI calls.
Let's go over some history in Navigator 3/4 first. LiveConnect is a technology developed by Netscape for Java and JavaScript communication, and it is used in both Navigator and Netscape Server products. In the past, LiveConnect can only used with the Netscape default JVM, because it made lots of assumptions how threading and security model works inside the JVM. In Navigator 3/4, JavaScript->Java communication is done by straight JNI calls. As you may know, using JNI normally will bypass all the security checks in JDK/JRE. However, because of the security model used in the Netscape JVM, security will still be checked if the call is issued from JNI. Java->JavaScript communication is again done by providing a netscape.javascript.JSObject implementation, which calls back into native code through JNI. Again, security will still be checked because of the security model in the Netscape JVM. One other note is that the JavaScript engine and the Netscape JVM use the same security model for security checks, lots of security information are implicitly shared between the JavaScript engine and Netscape JVM in LiveConnect.
Now, let's come back to the Navigator 5 reality. OJI will allow any JVM vendors to plug their JVM into the browser. The LiveConnect model is now broken because the JVM does not use NSPR and does not use the Netscape security model. Rewritting LiveConnect is not an option either, because LiveConnect code is used heavily by other Netscape products, and the JS and LiveConnect team at Netscape is not willing to rewrite it just for us. Thus, the only option we have is to emulate it as much as we can, we achieve this goal by the following:
- nsISecurityContext: This is an interface we define that encapsulates the current security context in either the JavaScript or the JVM. Notice that LiveConnect is basically either JS->Java, or Java->JS communicator, so there is a need to pass the security context from one boundary to another, and this is the task of nsISecurityContext. In JavaScript, nsISecurityContext contains the JavaScript execution state, and some other JavaScript execution stack related information. In Java, nsISecurityContext basically is the AccessControlContext in the Java thread.
- nsISecureEnv: In LiveConnect, thousands of JNI calls are used for applet method invocation. By default, JNI is not secure. If any application is able to get a hold of the JNIEnv pointer, it can do anything it wants, and the security checks are completely bypassed. However, JNI in Navigator 3/4 is secure basically because the JVM and the JavaScript engine share the same security model. On the other hand, in Navigator 5, this represents a big problem because our JVM have a totally different security model.
To address this problem, we designed an interface called nsISecureEnv. nsISecureEnv have exactly the same methods like JNIEnv, except some of the methods take one extra param -- nsISecurityContext. As described above, nsISecurityContext is an interface that encapsulates the security context. In this case, nsISecurityContext represents the security context in the JavaScript side when the method is called through nsISecureEnv (or JNIEnv). For normal JNI call through JNIEnv, the method is invoked directly in the JVM. However, in nsISecureEnv, only certain JNI methods will be invoked directly through the underlying JNIEnv, if security is not an issue. For example, GetMethodID, etc. For other methods that security is an issue, the call will actually performed through Java Reflection using nsISecurityContext as the security context of the call in the JVM. By using Reflection, we are able to setup the correct stack frame with the right permission, so proper security checks will be triggered during method invocation. When there is a security check, the nsISecurityContext passed in nsISecureEnv will actually get called to determine if certain action is allowed on a security target.
In Navigator 5, nsISecureEnv is exposed as the only way to make JNI call through the OJI plug-in, and the real JNIEnv is never exposed. In this way, any components trying to make JNI call will be forced to pass an extra param nsISecurityContext in order to make the call. If nsISecurityContext is passed as NULL, the call will be treated as from an untrusted source.
Remember that LiveConnect engine uses JNI heavily, but not nsISecureEnv, and it is impossible to ask the JavaScript team to change it. The workaround is to create another object called ProxyJNIEnv. ProxyJNIEnv looks exactly the same as JNIEnv. The main difference is that ProxyJNIEnv will not called into the JVM directly. Rather, every ProxyJNIEnv is associated with a nsISecurityContext. Whenever any method in ProxyJNIEnv is invoked, it will call nsISecureEnv in the OJI plug-in, with the nsISecurityContext that it associated with. The advantage of this scheme is that all the existing browser code that uses JNIEnv will not need to be rewritten. The only trick here is that the browser has to know how to get the ProxyJNIEnv to pass in these browser code. The other advantage is that the browser now can give out JNIEnv to any of its components. Because the JNIEnv seen by other components is actually ProxyJNIEnv, it will always have a nsISecurityContext associated with it, so the browser can handle out a "No security" ProxyJNIEnv to trusted components, and "Untrusted" ProxyJNIEnv to untrusted components.
Because of this extra indirection for making JNI call, some OJI plug-ins can also take advantage of it to perform thread switching if necessary. Remember that the browser and the JVM may use different threading model or in different processes, so calling JNIEnv in the JVM directly from the browser is not possible. By using nsISecureEnv, the threading switching or IPC communication can all be hidden in nsISecureEnv.
Also notice that the layout engine and JavaScript engine are on the main thread in Navigator 5, so all the calls through nsISecureEnv will be in the main thread. By using nsISecurityContext and nsISecureEnv, the security and threading issue in JS->Java communication is solved.
- nsILiveConnect: In LiveConnect, Java->JS communication is through netscape.javascript.JSObject. This is a Java wrapper that allows the applet to access the document object model (DOM) of the current document. In Navigator 5, nsILiveConnect provides a way to navigate the DOM in the native code. However, because JSObject is a Java wrapper class, it can be called from any Java thread in the applet. Also remember that all XPCOM/OJI interface should be called in the main thread only, so we are restricted to call nsILiveConnect from the main thread as well. As a result, all the callbacks from netscape.javascript.JSObject will need to be marshaled into the main thread, then the call can be executed. The marshaling is done through nsIThreadManager in XPCOM, and it provides a way to post a execution request in the main thread. When our request is finally executed in the main thread, it will call nsILiveConnect to access the DOM. In Windows, the OJI plug-in is in-process, so the marshaling involves only packaging the params when netscape.javascript.JSObject is called, post a request in the nsIThreadManager, carry out the request, and return the result into the original thread. In Solaris, it is more complicated because the OJI plug-in is out-of-process. Thus, the marshaling will involve communication between the browser and the JVM in two separate processes through IPC.
One thing is still missing: security!! This time, nsISecurityContext is used to encapsulate the security context in Java -- i.e. AccessControlContext. When netscape.javascript.JSObject is called, the current Java stack state will be taken in the AccessControlContext object, and pass it back to the native code. Before nsILiveConnect is actually call, AccessControlContext will be wrapped as a nsISecurityContext and pass along. Thus, if there is any security check in the LiveConnect engine when nsILiveConnect is called, the security check will eventually ask the nsISecurityContext to determine if certain action is allowed on a security target
Notice that all calls in nsILiveConnect occur in the main thread only. By using nsISecurityContext and nsILiveConnect, the security and threading issue in Java->JS communication is solved.
- Nested calls: What happen if JS->Java->JS, or Java->JS->Java? How does security works in these cases? In these cases, the mechanism is the same: nsISecureEnv is used for JS->Java, and nsILiveConnect is used for Java->JS. The intereresting thing is the chaining of security context. In the situation of nested calls, the security context used for execution is always determined by the original caller in the chain. For example, if JS->Java->JS, and the first JS is trusted, Java and second JS is untrusted, then the call in JS should eventually be executed by using a trusted security context because the original of the caller is trusted. To achieve this effect, the nsISecurityContext that is passed in nsISecureEnv and nsILiveConnect always encapulates the security context of all the caller in the current call chain. Let's see another example: JS->Java->JS->Java.
JS-1->Java -- securityContext1 represents the security context in 1 is passed to nsISecureEnv.
JS-1->Java-2->JS -- securityContext2 represents both the security context in 2 and securityContext1 is passed to nsILiveConnect
JS-1->Java-2->JS-3->Java -- securityContext3 represents all the security context in 3 and securityContext2 is passed to nsISecureEnv
Whenever there is a security check in the last Java call, it will trigger the check in securityContext3, and that will trigger the check in securityContext2, and eventually that will trigger the check in securityContext1, so the actual security context in JavaScript in 1 will be used to determine if certain action is allowed on a security target.
Notice that the nsISecurityContext represents the AccessControlContext object in the Java side in Java->JS call, and nsISecurityContext represents the JavaScript execution state in the JS side in JS->Java call. When there is a security check in either JS or Java side, it will eventually call nsISecurityContext to check if certain actions is allowed on a security target. Currently, Java does not understand any JavaScript security target except AllPermission, and JavaScript does not understand any Java security target either except AllPermission. Thus, security context propagation is only useful for JS if there is more than one JS->Java call in the call chain. Similarly, it is only useful for Java if more than one Java->JS call occur in the call chain. However, in the future, it is completely possible to map security targets between Java and JS, so security context propagation can be used in both Java and JS no matter what the security target is.
This summaries the general scheme for security context propagation between JS and Java.By using nsISecureEnv, nsISecurityContext and nsILiveConnect, threading and security issues are completely abstracted out, and LiveConnect is now possible to work with different JVMs in Navigator 5.
How to obtain Mozilla source:
The offical documentation for how to obtain the Mozilla source is at http://www.mozilla.org/cvs.html.
Assuming you are running Windows NT, you can also do the following:
- Install CVS from http://www.cyclic.com/cvs/windows.html.
- Open the command prompt in Windows NT.
- Set the following:
- set CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
- set USERNAME=anonymous
- set CVS_PASSWORD=anonymous
- Login using cvs login and use anonymous as password.
- Obtain the source by cvs -z3 checkout SeaMonkeyAll
Notice that HOME environment variable must be set to a sensible directory, or cvs will complain. Also, CVS cannot be used over proxy server or firewall, so make sure your machine can connect to www.mozilla.org directly.
Because people can check in stuffs into mozilla.org anytime, it is possible that the tree that you obtain from mozilla.org is broken. Thus, before pulling down the Mozilla tree, use tinderbox to verify the state of the SeaMonkey tree is "green" in your platform, before the pulling. Otherwise, this is a waste of time.
The other issue is that there is a nightly build of Mozilla, and you can pull the nightly build by setting the date in the MOZ_DATE environment variable before the pulling. However, We have found several times that even the nightly build was broken. Thus, don't trust the nightly build -- always pull the tree only if the tree is "green" in tinderbox.
Also, if you are running Windows, pulling the source in Windows NT on a NTFS partition is highly recommended. If you are running Windows 95/98, don't bother to pull the source because all the long filenames in the sources will get messed up, and you won't be able to build it. If you are running Windows NT with FAT or HPFS partition, it should work, but I haven' t tried it myself.
How to build Mozilla:
The offical documentation for how to build the Mozilla source is at http://www.mozilla.org/build/win32.html. Please follow the instructions in this document, and install GNU Tools for Microsoft Windows and Perl5 for win32 on your machine. Also make sure you install the patch for the build tools as well.
One you install all the tools on your machine, please set the environment variables as follows:
set BUILD_OPT=
(set this to 1 if you want an optimized build)
set BUILD_XPIDL=1
(don't set this if you haven't installed the wintools.zip package in a while)
set MODULAR_NETLIB=1
set MOZ_BITS=32
set MOZ_DEBUG=1
(set this only if you want to build a debug build)
set MOZ_NT=351
(if running NT3.51)
set MOZ_SRC=
(top of your tree, for example: set MOZ_SRC=d:\mozilla_source if this is the directory where you checked out or unzipped the source into... don't end this line with a '\'... you'll be sorry if you do)
set MOZ_TOOLS=
(the parent directory of the GNU tools 'bin' directory. The build looks for MOZ_TOOLS\bin\gmake.exe, so make sure that the gmake.exe from the Windows Build Tools package resides there.)
set NGLAYOUT_PLUGINS=1
set OS_TARGET=WINNT
(or WIN95, or WIN98? Someone with one of these systems needs to verify this)
set STANDALONE_IMAGE_LIB=1
set _MSC_VER=1100
(if you are running VC++ 5.0) or 1200 (if you are running VC++ 6.0) - or - set MOZ_VCVER=42 (for version 4.2, though no reports of successful compilation have been reported with 4.2)
set BUILD_CLIENT=
(set this to 1 if you want to build the Navigator 5 UI, mail/news reader, and other good stuffs as well)To actually build Mozilla, do the following:
cd mozilla
nmake /f client.mak build_allIf you are running Windows, please make sure Mozilla is built in Windows NT, or it will not build at all.
Another interesting note is that BUILD_CLIENT is not documented in the Mozilla build instruction, but it is kind of a known thing that you must turn on in order to build the full version of Navigator.
Here is a basic layout of the tree:
\base -- basic Mozilla services
\build -- makefile
\caps -- Capability Manager used for security purpose
\config -- build configuration
\dist\public -- all the public header files
\dist\Win32_d.obj -- the resulting binary build
\dom -- Gecko Document Object Model
\editor -- Navigator 5 HTML Editor
\gfx -- Gecko Rendering Layer
\htmlparser -- HTML parser
\intl -- i18n related stuffs
\jpeg -- JPEG decoder
\js -- JavaScript engine
\js\src\liveconnect -- LiveConnect source
\layout -- Gecko Layout engine
\mailnews -- Navigator 5 Mail/News Reader
\modules -- XPCOM modules in Mozilla
\modules\oji -- OJI API
\modules\plugin -- New Netscape Plug-in API
\nav-java -- Java stubs to make old Netscape code to work
\network -- NetLib, Navigator Network Library
\nsprpub -- NSPR, Netscape Portable Runtime
\rdf -- Resource Definition Framework
\silentdl -- Silent Download, replacement for SmartUpdate
\sun-java -- Another Java stubs
\webshell -- Gecko ActiveX control wrapper
\widget -- Navigator 5 cross platform UI widget
\xpcom -- XPCOM
\xpfe -- New Navigator 5 cross platform UINotice that not all the directories are listed here, and I mainly list all the things you should know. Once Mozilla is built successfully, a special folder will be created under mozilla\dist, and the resulting binary is in mozilla\dist\Win32_d.obj. The main things in the binaries are viewer.exe and apprunner.exe under mozilla\dist\Win32_d.obj\bin. viewer is the executable for the Gecko layout engine, while apprunner is the new Navigator 5 UI that uses Gecko.
How to run Java Plug-in with
Mozilla:
To run Java Plug-in with Mozilla, you will need the latest Kestrel Java Plug-in. Please do the following:
- Build Mozilla.
- Make sure a version of Netscape Navigator 4.x is installed in the machine. This is for working around a bug in Mozilla. In the future, you don't need this step.
- Install Kestrel Java Plug-in.
- Run apprunner or viewer from mozilla\dist\Win32_d.obj\bin.
If this doesn't work, make sure you have created at least one user profile in Netscape Navigator 4.x. You can check it in "Program Files->Netscape Communicator 4.x->Utilities->User Profile Manager" from the Start menu.
Netscape frequently changes the XPCOM API that we rely on, so there are chances that the Kestrel Java Plug-in may get out-of-sync with the OJI API used in your Mozilla build. In this case, you either get an older Mozilla build to make it work, or you will need to update the code in Java Plug-in.
Who to contact with OJI issues:
Name Email Address Role Company/Organization Alex Musil amusil@netscape.com OJI engineer/manager, Netscape Plug-in Netscape Patrick Beard beard@netscape.com Former OJI engineer, Mac OJI plug-in/JavaScript Netscape Warren Harris warren@netscape.com Former OJI lead, Netlib/Mail & News/ XPCOM Netscape Suduharshan Srinivasan sudu@netscape.com Former OJI engineer, LiveConnect Netscape Raman Tenneti raman@netscape.com Former OJI engineer, security, signing Netscape Paul Wyskoczka paw@netscape.com OJI SQA manager Netscape Scott Furman fur@netscape.com JavaScript engineer, JavaScript, LiveConnect Netscape Jerome Dochez dochez@eng.sun.com Java Plug-in lead JavaSoft/Sun Stanley Ho stanleyh@eng.sun.com Former Java Plug-in engineer, Win32 OJI plug-in JavaSoft/Sun Nagendra Nagarajayya nage@eng.sun.com Java Plug-in engineer, Solaris OJI plug-in Solaris division/Sun Ben Gomes bgomes@eng.sun.com Former Java Plug-in engineer, Solaris OJI plug-in JavaSoft/Sun Tom Ball tball@eng.sun.com Java Plug-in Engineering Manager JavaSoft/Sun Graham Hamilton kgh@eng.sun.com D.E. working on various cool projects, including OJI JavaSoft/Sun Blake Connell blake.connell@eng.sun.com Java Plug-in Product Manager JavaSoft/Sun Gemma Riner gemma@eng.sun.com Java Plug-in SQA manager JavaSoft/Sun Vijay Manda vmanda@eng.sun.com Java Plug-in SQA enginner, OJI JavaSoft/Sun Li Gong li.gong@eng.sun.com D.E., Java Security JavaSoft/Sun Jan Luehe luehe@eng.sun.com Java Security engineer, signing, OJI signed applet support JavaSoft/Sun George Drapeau drapeau@eng.sun.com Mozilla OJI project owner Sun/Netscape Alliance(??) Gabriel Lawrence gabriel.lawrence@eng.sun.com Java related development in Mozilla Sun/Netscape Alliance (??) Jim Laden jladen@eng.sun.com MDE engineer Computer System/Sun
More Information:
Not every aspect of Java Plug-in are documented in this page. However, for more information about each major features, you can find them in the online documents:
- HTTP - Hypertext Transfer Protocol Overview
- SOCKS Proxy Protocol
- Using the Client Autoconfiguration File
- Netscape Cookies
- Netscape Communications: Cookies and Privacy FAQ
- Persistent Cookie FAQ
- Mozilla Home Page
- XPCOM Home Page
- Netscape Plug-in Guide
- Extending Mozilla
- Netscape DevEdge Online
- LiveConnect Overview
- JavaScript Technote - JAVA, JAVASCRIPT AND PLUG-IN INTERACTION USING CLIENT-SIDE LIVECONNECT
- Using LiveConnect
- Signing Software with Netscape Signing Tool 1.1
- Object Signing Resources
- Netscape Object Signing- Establishing Trust for Downloaded Software
- MSDN
- Java Plug-in Documentation
- Java Plug-in FAQ
Please email me
if you have question.