Skip to main content.
August 27th, 2008

Extract All Classes Loaded in the JVM into a Single JAR

Today I needed to optimize the file size for a commercial Java applet (Web form signer) that my team is developing in the last month. We use few external libraries (Bouncy Castle Crypto API and few others) and these libraries are above 2 MB in several JAR files. If we were developing server side application, it would not be a problem, but when we are building an applet, the size of the applet and all its JARs matters.

I needed to remove all unused classes from the JARs that my applet was including a part of itself. For example the Bouncy Castle JARs were about 1,6 MB but the applet used only a small part of all algorithms and standards implemented by these JARs.

Extracting All Classes Loaded in the JVM

My final goal was not only to remove all unused classes from all JAR files but also merge these JARs along with the applet classes into a single JAR file that has the smallest possible size. I came with the idea to run the applet, to go through all its functionality and to get a list of all classes currently loaded into the JVM executing the applet. At this moment all classes required by the applet for its normal work will be loaded in the JVM and all classes that was never used by the applet will not be loaded in the JVM. If I package all these classes into a new JARs, it will contain the minimal set of classes nedded by the applet along with the applet classes.

As fas as I know how the JVM and the class loaders behave, this should be correct - we can expect all classes required by the applet to be loaded in the JVM after its entire functionality is accessed at least once.

I had a serious problem: how to get a list of all classes loaded in the JVM.

List All Classes Loaded in the JVM

Geting a list of all classes that are loaded in the JVM at some moment is not easy job. We can write Java agent through the java.lang.instrument API but I needed to do this at runtime (just to add few lines to the applet). I found in Google a very nice class for accessing all classes loaded in the JVM written by Vladimir Roubtsov and published in Java World (http://www.javaworld.com/javaworld/javaqa/2003-07/01-qa-0711-classsrc.html). With few modifications it successfully listed all classes loaded in my applet.

Create a Single JAR with All Classes Loaded in the JVM

The next step was to create a single JAR with all classes loaded in the JVM. This was not complex. I created a class with few methods for copying all currently loaded classes into some directory specified as parameter. Here is the source code:

It is not a rocket science. I go through all classes loaded by the current class loader and by the system class loader, get their fully qualified name (e.g. org.bouncycastle.cms.CMSSignedData) and their source URL location (e.g. jar:file:/C:/PROJECTS/GeneratePKCS7andVerify/lib/bcmail-jdk15-140.zip!/org/bouncycastle/cms/CMSSignedData.class) and I copy their binary contents (from the URL) to the destination folder (into a .class file). In the mean time I recreate the package structure (following the full class name with all its packages). Finally I get a directory containing all class files loaded in the JVM at the time of caling my method and I can manually package them in a JAR (removing beforehand all system Java classes). That’s all. I use slightly modified version of ClassScope.java.

You can download a fully functional example here (Eclipse project): ExtractAllClassesFromJVMIntoJAR.zip.

Posted by nakov as java, blog at 11:32 PM EEST

Comments Off

August 25th, 2008

BGJUG Meeting - Java FX (28 August 2008)

The next meeting of the Bulgarian Java Users Group (BGJUG) will be held on 28 August 2008 in the Chemistry Faculty, Hall 210 in Sofia, starting at 18:30.

The topicwill be the Java FX technology. Speaker will be Naiden Gochev.

Posted by nakov as news, java at 2:08 PM EEST

Comments Off

August 24th, 2008

JSObject is not Thread-Safe

In one of my last projects I was working on Java applet that needed to digitally sign data forms at the client side in a Web browser. I with my team developed the applet and it did the job well. Unfortunately our customer decided to put multiple instances of the
applet in a single Web page. This resulted to unexpected behaviour: sometimes (from time to time) the browser window hangs. You can achieve this by refreshing the browser window continuously very fast pressing [F5] key many times). Strange problem, right?

JSObject is not thread-safe

Initially I thought that this is some kind of threading issue because:

After experimenting with lots of examples I found that the problem is related to JSObject. I created simple applet and it was able to run with multiple instances. After that I added access to the browser DOM by using JSObject.getWindow(this) and the “hang” problem was introduced.

It was clear that the JSObject class is not thread-safe and this causes the unregular hangs of the browser window. When we have several instances of the applet running in different browser windows we don’t have this issue. It appears only when we have several applets on a single Web page. The reason is simple: when multiple applets are running in the same browser window, all of them share the same instance of the JVM (Java Virtual Machine). In the same time all these applets share the same browser window and thus the same browser DOM tree. This means that JSObject.getWindow(this) could be called by multiple threads in the same time.

JSObject is not thread-safe

To overcome this problem we synchronize all code accessing JSObject by JSObject.class. Why JSObject.class? In a single virtual machine this class should be loaded only in the JVM so synchronizing by it will block multiple threads runngin in a single JVM to access JSObject at the same time.

Below is a sample applet that illustrates how to perform such synchronization:

If you remove the synchronization of the code above, and put the applet several times in a single form, it will randomly hang the Web browser.

Posted by nakov as java, blog at 5:29 PM EEST

Comments Off

August 20th, 2008

Debugging Java Applets in Eclipse

Today I needed to debug Java applet running in Internet Explorer from Eclipse. I was not straightforward. Let me share the experience how to do this:

1) First enable remote debugging in the Java Plugin:

a) Start –> Settings –> Control Panel –> Java –> Java Applet Runtime Settings –> View

b) Add the following to the “Java Runtime Parameters”:

-Djava.compiler=NONE -Xnoagent -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n

Java Plugin - Runtime Settings

This will enable remote debuging on TCP port 8000 for all applications running inside the Java Plugin (in Internet Explorer). Make sure this port is not used by other applications.

3) Close all Web browser Windows

4) Put breakpoints in your source code (you need to have an Eclipse project containing the applet source code)

4) In Eclipse create a remote debugging configuration:

a) Run –> Open Debug Dialog –> Remote Java Application –> New

b) Assign host = localhost and port = 8000

Eclipse - Remote Debug Configuration

Press the “Debug” button and enjoy debugging.

Note: Don’t forget to build your applet with debug information (javac -g). I am buidling my applet with ant so I just added <javac debug=”true” … />.

Posted by nakov as java at 6:53 PM EEST

Comments Off

August 19th, 2008

Reading File Contents in Firefox 3 and Other Browsers

In the last few weeks I work on a project about digitally signing Web forms. I need to develop a Java applet that signs Web forms (all form fields along with the attachments). The way we want to implement this is to use signed applet (running in the client Web browsers without any security restrictions) that collects all forms fields and their values, save them into a XML document, digitall signs the XML (using a private kay comming from a PKCS#12 keystore or PKCS#11 smart card) and finally produces PKCS#7 SignedData object (containing the XML, the signature and the certificate and the entire certification chain of the signer).

Not All Browsers Support Reading the Full File Path from <input type=”file”>

All runs well except that the applet should read the contents of all files that are selected for uploading along with the Web form (in order to include their content in the XML). Thus the applet needs the exact location in the file system for each uploaded file. The usual solution for this problem is to get the full file path and file name of the selected for uploading files from the Web form (e.g. document.forms[0].fileToUpload.value).

This works well in the following browsers:

In all of the above Web browsers whn you acces the “value” property of the file upload control (<input type=”file”>) you get the file name along with the full path to the selected file (e.g. “C:\Documents and Settings\All Users\Documents\My Music\Sample Music\New Stories (Highway Blues).wma”).

In some browsers due to privacy policy only the file name (without the path) is returned (e.g. “New Stories (Highway Blues).wma”). I found that the following browsers do not allow accessing the full path of the uploaded files:

Firefox 3 Supports Reading File Contents from JavaScript

I found a way to read the file contents from JavaScript in Firefox 3. It is pretty easy:

This opens a way to workaround the problem in FF3 because my applet can read the file contents of the selected for uploading files directly from the Web browser (instead of taking the full file path and reading the file contents in Java).

See an example of how this works: Reading file contents in Firefox 3 - Example.

Opera 9 Does Not Supports Neither Reading File Contents Nor Full File Path

I still don’t have a solution for Opera 9. I tested with Opera 9.51 and found that it does not provide a way to take the full file path of а file selected for uploading and it also does not have API for reading file contents. Maybe some day such API will become a standard (there is an official W3C draft here: http://www.w3.org/TR/file-upload/) but until this day we cannot support Opera.

Posted by nakov as blog at 3:54 PM EEST

Comments Off