Skip to main content

The clickwrap JAR installer sucks!

10 replies [Last post]
hlavac
Offline
Joined: 2003-09-16

Someone please slap the programmer that wrote the clickwrap JAR installer that is used to distribute Mustang API docs and source! It is terribly, painfully slow!!!!

Main source of problem seems to be the com.sun.tools.extractor.KeyedInputStream.fill() method, according to the Netbeans profiler ;)

How the hell can someone write code that takes two minutes on A64 3200+ to xor a file with a repeating sequence of bytes
"YES I ACCEPT THE CLICK THROUGH LICENSE. "?! Following code does the same in one second on my machine:

<br />
package clickthrough;</p>
<p>import java.io.BufferedInputStream;<br />
import java.io.BufferedOutputStream;<br />
import java.io.FileInputStream;<br />
import java.io.FileOutputStream;</p>
<p>public class Main {</p>
<p>    static byte[] wrap_key = {'Y','E','S',' ','I',' ','A','C','C','E','P','T',' ','T','H','E',' ','C','L','I','C','K',' ','T','H','R','O','U','G','H',' ','L','I','C','E','N','S','E','.',' ',' '};</p>
<p>    public static void main(String[] args) {<br />
        try {<br />
            FileInputStream fin = new FileInputStream("X_X");<br />
            try {<br />
                FileOutputStream fout = new FileOutputStream("X_X.jar");<br />
                try {<br />
                    BufferedInputStream in = new BufferedInputStream(fin, 1024*64);<br />
                    try {<br />
                        BufferedOutputStream out = new BufferedOutputStream(fout, 1024*64);<br />
                        try {<br />
                            int b;<br />
                            int pos = 0;<br />
                            while ((b = in.read()) != -1) {<br />
                                b = b ^ wrap_key[pos];<br />
                                pos++;<br />
                                if (pos >= wrap_key.length) {<br />
                                    pos = 0;<br />
                                }<br />
                                out.write(b);<br />
                            }<br />
                        } finally {<br />
                            out.close();<br />
                        }<br />
                    } finally {<br />
                        in.close();<br />
                    }<br />
                } finally {<br />
                    fout.close();<br />
                }<br />
            } finally {<br />
                fin.close();<br />
            }<br />
        } catch (Throwable t) {<br />
            t.printStackTrace();<br />
        }<br />
    }<br />
}<br />

Now start crying again about how users are unfairly perceiving Java as being slow! It's stuff like this that keeps the infamous Java is slow myth floating...

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
hlavac
Offline
Joined: 2003-09-16

I spent last evening making a prototype replacement clickwrap installer ;-)

I found that I can achieve much faster startup time by tuning the order of files in the JAR file and their compression levels.

I also found that I could achieve about twice as good compression factor when the inner archive (containing the actual payload) is not compressed, and is added as a signle compressed file into the wrapping archive. Compression works much better due to the larger context. Unfortunately it requires one more level of wrapping or doing the compression explicitly due to obfuscation lowering compressability of the data, but that is not a problem.

I'm making an application that creates the selfextracting JAR archive that can be used as part of the build process. I think I will have it working this evening ;) Mybe later I'll even make a custom Ant task for it ;)

I'm also looking at providing support for headless (GUI-less) extraction for machines without AWT.

I would like to know:

- what are the exact (legal) requirements for a clickwrap installer? Would it be possible to provide it with a hidden commandline parameter that would mean I accept the license, and show it on the end of the license, or does it require explicit interactive interaction with a human, like typing something (dynamically generated) so that it cant be trivially scripted? It's especially important for the headless extraction...

- Is it ok for the obfuscated archive to have such a weak obfuscation algorithm as the original installer? (I did not need to look at the code to find out what it does - it was obvious from the obfuscated file itself! Using XOR with periodic plaintext on files that contain lots of binary zero chunks is a very bad idea ;-))
At the moment I do the same obfuscation method for the payload, but I know much better ways to do that ;-)

BTW - anyone knows an easy way to get last modified time of a resource (which might come from a file, JAR archive, or somewhere else)?

tackline
Offline
Joined: 2003-06-19

I'm kind of interested in the way programmers think of exceptions. Why is it necessary to use try/finally on the buffered streams? All that is necessary is to close (flush) the BufferedOutputStream in the non-exception case. Nice to see you didn't do that weird 'if not null close' thing. Also, what is the point in dump a trace instead of declaring a throws clause for main?

hlavac
Offline
Joined: 2003-09-16

I close buffered streams because it frees up the backing buffer. I do that to free as many resources as soon as possible, even in case of an error/exception. Stuff that is left referenced when going out of the scope will be freed at method exit time, not at the going out of scope time... I should probably even null the streams ;)

Catching excetions in main like this - I do that because sooner or later, I will change this to some more elaborate exception processing mechanism - you probably dont want to just dump the exception to the stderr, you will want it logged or displayed in a nicer way, or directed to stdout...

cowwoc
Offline
Joined: 2003-08-24

+1

If you're correct this should really be fixed :) I suggest you open up a bug report against it. Include the implementation you mention below.

Gili

hlavac
Offline
Joined: 2003-09-16

I would, but I'm not sure if it can be considered part of the Mustang - probably its just some Sun internal app, and I have no idea where to post a bugreport/RFE for it.

kellyohair
Offline
Joined: 2004-09-03

Go to:

https://mustang.dev.java.net/collaborate.html

If you submit the bug, I'll walk it through the system and get it into Mustang. I know it's a little red-tape to do the bug submission, but I do want to make sure you get credit for the fix, and the fix gets formally into Mustang.

This extractor code was thrown together rather quickly, so I'm not surprised it has a few performance issues. Thanks for looking at it and taking the time to point out the problem.

hlavac
Offline
Joined: 2003-09-16

Ummm I did what you suggested but I think it ended in a wrong place ;-)

https://mustang.dev.java.net/issues/show_bug.cgi?id=2

hlavac
Offline
Joined: 2003-09-16

Now i filed a RFE bug against Mustang, that should be more appropriate ;)

hlavac
Offline
Joined: 2003-09-16
kellyohair
Offline
Joined: 2004-09-03

Got it. I'll see what I can do.