Mixing java, ruby and javascript in a modern web app

by We didn't write this

After getting sick of only programming Java for 4 years in college and at my first 2 jobs, I came began to feel like Java was nothing more than a tool to transform XML files into stack traces. Given the variety of cool developer jobs in the bay, I made the easy choice to switch things up. So, I spent a few weeks learning Ruby On Rails and surfing craigslist for a new, java free gig. I was fortunate to quickly snag a job at a small, young and ridiculous in a good way web development shop that was way, way, way too cool for Java. Mission accomplished. Unfortunatley, when the requirment came to build a web app that did complicated things on a users local filesystem from a browser, a java plug in seemed like the best way. Since everyone was way, way, way too cool for Java the project was mine, and on my first day in my super cool, San Fransisco, ruby on rails development job, I installed Eclipse Java edition and started writing public void init main(String[]args) Fail.

We set out to build a web page that is able to download firmware update files to a camera plugged into the user’s computer. This way, a user could update software on their product through a web app and hence without installing stuff to their operating system..

Such a task cannot be accomplished without a plugin. After briefly considering Flash and Silverlight and then realizing that neither us, our friends or our friend’s friends actually new anything about those technologies, we settled on a Java Applet. Assuming the user has Java installed in their system and enabled in their browser, such an applet can access the user’s file system and make changes to it. Specifically, we used the applet to scan the user’s file system, detect the presence of an external device plugged in via USB, and download firmware update files to this device.

Java applets are a 15 year old outdated technology. This causes difficulties. First and foremost, applets have a pretty ugly user interface. To avoid having the user interact with a 2 decade old Java Swing based UI and stay constant with our client’s brand, I chose to hide the applet and call it’s functionality with Javascript. This way, the user can see a well styled HTML page but still benefit from Java’s powerful abilities.

Embedding an applet in a web page is super easy. Place the jar in the public directory of your project and include it in your HTML with

<applet name=”dummyApplet” archive=”yourCode.jar” code=”DummyApplet.class” codebase=”/” height=”0″ width=”0″></applet>

By setting the height and width of the applet to 0, it is invisible to the user. I also found that codebase had to be set to “/” or the applet was not found. To interact with the Java program, you can call it’s methods directly. In the example above, you would call

document.dummyApplet.appletMethod(),

where dummyApplet is the name of the applet in the HTML.

The cool thing about using an applet is that Java is a general, all purpose language that can do just about anything on the user’s filesystem. Unfortunately, most browsers prevent plugins from doing stuff outside of the browser sandbox. Because we had to download update files to specific places in the user’s drives, we needed more permissions than this. Therefore, we signed the applet, meaning we gave the Java routine a signature with the client’s brand that the user had to accept. Once the user accepted the signature, the applet operated like a native operating system program, with full privileges to do whatever it needed on the user’s computer.

To sign my applet I used an oracle utility called JarSigner. For me, this was a bit difficult because I had to use an existing private and public key pairing provided to me by the client. Therefore, I had to integrate these keys in my personal keystore, which proved to be a royal pain in the ass; I learned much, much more than I wanted to know about PEM and DEB key formats. However, if you are generating your own keys, things should be much more straight forward.

Obviously, using an applet is very powerful. By compiling a bit of Java code and serving it to the user, we were able to basically create an application that did stuff an installed program might do, but through a web page and without having the user install anything. Our specific goal was to install binary files to a camera plugged into the user’s computer. Once the user allowed the Java routine access into their file system, it was able to scan their drives, find the plugged in USB device, and download the right files into the right place. These Java actions were initiated by javascript so to the user, it looked like they were simply clicking on slick, well designed buttons. As an added bonus, Java is multithreaded while Javascript is not. As a consequence, I used Java’s multi threading capabilities to run complicated, time consuming routines on the user’s machine without locking up the UI. For example, to download a large file to the user’s machine, I kicked off a new java thread and then used a Javascit timer function to check on the progress of this thread as it executed. In this way, I was able to do pretty complicated, boring, backend stuff on the user’s computer while sumultaneously provididing the user with a pretty, brand consistent, styled progress bar that showed the progress of these actions. (As an aside, I found that I had to start my threads using the AccessController.doPrivilegedAction method, or they did not have appropriate permissions, even though the applet was signed. If you are reading this, and this helps you, good luck and I am sorry.)

This is Tara on Cannibals, 12d at Donner Summit, California. Its not really a great photo, and it has nothing to do with this post. However, its here and you already looked at it, so suck it.

Of course, there is a downside. Java is a plug in, and many users do not have it installed. Furthermore, the ability for a web developer to build these types of thing using java makes it a huge security risk. While I was developing a useful updating tool, someone else could have easily designed something similar that installed malicious binaries to the user’s file system for unholy, bad causes.

Since web apps like this can be exploited to infect a user’s filesystem, many modern browsers and operating systems attempt to block them. We ran into several issues where browsers automatically blocked execution of Java applets. While this is probably good in general, since it stops the propagation of viruses, it was bad for our cause, since it caused the web app to fail in a variety of ways. In general, Java failed in an incredibly colorful variety of ways on each operating system and browser. Dealing with behaviour like this is very difficult when designing a user interface. When the browser starts locking up and throwing ninja warning bars its very hard to detect why its happening and recreate it consistantly. As a consequence, its supremely difficult instruct the user how to fix their java. Sadly, while Java runs flawlessly in microwaves, cellphones, and credit cards, it often simply can’t handle a macbook air. In short, it might be best to open your fridge, snag some leftovers, throw them in the microwave and let Java heat up your lunch while building your firmware update tool with more fit, predictable technologies.

To account for such failures, we basically had no other choice but to make an alternative flow through the update process that allowed the user to download the files without an applet and still update their camera manually. This manual process was much more cumbersome. Without Java, the user had to download the update files in a compressed zip, unzip them, and then drag them over to their final destination. So, while with Java it was a one click process, without Java, it was a multistep hassle that required semi advanced computer knowledge. However, I feel required to note that unzipping these files still seemed much easier than trying to install Java on an operating system and enabling it in a browser. Java tended to play hard-to-get like a tipsy sorority girl, sometimes cooperating but often acting out in unpredictable and confusing ways.

In the end, when the applet worked, it was slick. However, the applet failed, A LOT, for many users, so its not really a comprehensive solution. Furthermore, with modern browsers moving towards HTML5 and away from plugins, such web apps are going to not work more and more in the future. As a blatant example, the latest version of Chrome does not run the latest verison of Java, so we basically had to not support the most advanced browser in the world.

Perhaps the most cumbersome part of the app was deciding whether or not Java might work for a user. There are many methods of doing this, some including Java and some not. I would compare trying to solve this problem to falling off a cliff and being not sure whether you are too injured to walk. You can certainly look at your legs, look for bruises, check for sensation, and make predictions based on that. However, the only sure way to know whether your legs work or not is to get up and try to take a step. Similarly, in the end, we found that the only 100% percent reliable way of knowing whether Java works for a user is trying to execute some Java commands and seeing if they fail. So, we loaded a small test applet with only one method that returned true. Then, we tried to interact with it. If the method returned true, we allowed the user to proceed using Java. Unfortunately, the applet never really returned false, the javascript just errored trying to communicate with it. However, I took the hint and assumed java was fucked in this case.

In the end, it was a damn cool project. We really go to stretch the limits of what a web page should and should not do, and made a slick product. It did things magically and provided an awesome user experience. However, in many cases, Java simply failed. Clearly, its not a comprehensive solution. If I had to do it again, I would probably look into writing a native executable that could be downloaded to the user’s file system and then installed the files in the right place. Sure, this would technically no longer be a web app. However, it would certainly be more error proof and reliable than a browser plug in.

On the climbing front, I havent climbed for a week both to unwind after El Cap and put in a cool 65 hour work week of releasing a web app. It was especially cool to send as a full time employed weekend warrior. A 4 day climb with a rest day was not an option. On our climb we met several people that took 3 or 4 days to climb it with a “it will take however long it will take, and thats all good” attitude. We had no such margins. If the push took too long and I called my work on Monday morning saying “hey listen, I am really close on freeing the Freerider, but I have to bivy at round table ledge so I can send tomorrow morning” they would say “we don’t know what “freerider”, “bivy”, “send”, or “round table” means, but we do know what “monday morning” means and if you aren’t here by 10am, you are fucked.

Maybe its time to quit climbing while ahead and pick up something more profitable and useful, like beach volleyball or competitive cup stacking. However, I do have some unfinishe business with an incredible mixed route “Father’s Day” at Donner Summit last weekend. This climb is spectacular, an overhanging, 40 foot 13a gear protected hand crack to a v9 boulder crux with huge moves on underclings and side pulls, for a 14a mixed route that’s one of the best single pitch lines in California.

After spending the last month hiking to the top of El Cap 3 times, rapelling the whole cliff twice, and finally climbing it, it felt amazing to go cragging.

There is something to be said for taking off your shoes under a climb and returning to them 25 minutes, not 2 days, later. However, it just seems so damn foolish to climb anywhere besides Yosemite, where the undisputably most badass cliffs in the world are practically in our back yard. Yosemite is hard, scary, and brutal, but the thought ignoring it and climbing elsewhere might be even worse.