Clojure Programming/Examples/Creating an Applet

From Wikibooks, open books for an open world
Jump to navigation Jump to search

This tutorial explains how to create a simple "Hello World!"-applet. The article also explains how you can sign your applet (if Reflection is needed).

A demo page is available at [1].

Preparation[edit | edit source]

Create a new directory, let's call it "~/cljapp" here. Copy the file "clojure.jar" into this directory (this article was tested with version 1.0.0).

Clojure code[edit | edit source]

Create a subclass of javax.swing.JPanel and add an implementation for the paint function. Save the file at "~/cljapp/src/applet.clj".

(ns applet
  (:import (java.awt Graphics Color Font RenderingHints)
           (javax.swing JApplet JButton))
  (:gen-class
     :extends javax.swing.JApplet))

(defn -paint [#^JApplet applet #^Graphics g]  ;type hint avoids Reflection, then it works without signing
  (let [width (.getWidth applet)
        height (.getHeight applet)]
    (doto g
      (.setColor (. Color YELLOW))
      (.fillRect 0 0 width height)
      (.setColor (. Color BLACK))
      (.drawRect 0 0 (dec width) (dec height))
      (.setFont (Font. "Serif" (. Font PLAIN) 24))
      (.drawString "Hello World!" 20 40))))

This will show a yellow rectangle with a black border, containing the black text "Hello World!".

Note the type hints for the parameters of the -paint function which are used to avoid Reflection. Reflection is a bad thing for an applets, since it has to be signed then, and even then a warning message is displayed to the user. But since we do not want the user to be confronted with a daunting warning message, we should avoid Reflection which is possible here by adding type hints.

Creating the JAR[edit | edit source]

Now we compile the Clojure code to Java classes and put the files into "~/cljapp/cljapp.jar" (note for Windows users: use "-cp ../clojure.jar;." instead of "-cp ../clojure.jar:.", i.e. a semicolon instead of a colon as the path separator):

cd src
java -Dclojure.compile.path=. -cp ../clojure.jar:. clojure.lang.Compile applet
jar cf ../cljapp.jar .
cd ..

The contents of the JAR file should then look like this:

/META-INF
	/MANIFEST.MF
applet$_paint__1.class
applet.class
applet.clj   (you can omit the file if you do not want to distribute the source)
applet__init.class

Signing the JAR[edit | edit source]

(You can and should skip this section in many cases)

Before I mentioned that we should avoid Reflection in our applets. However, this is not possible in all cases. Then we have to sign the applet:

First, create a key and certificate, as described in many tutorials on the web. Here is a short summary:

Use keytool to create a new key (replace MyAlias by any name, see the keytool documentation for more details about the other arguments):

keytool -genkey -alias MyAlias -dname "cn=MyCompanyName, c=en"

Remember the password which is queried from you, we will need it later of course. Then, create a certificate:

keytool -selfcert -alias MyAlias -dname "cn=MyCompanyName, c=en"

Now we can sign the file "clojure.jar" (we do not need so sign our own applet):

jarsigner clojure.jar MyAlias

Creating the HTML page[edit | edit source]

We need a container for our applet, here is a simple HTML page, which we will save as "~/cljapp/cljapp.html".

<html>
  <head>
    <title>My first Clojure applet</title>
  </head>
  <body>
    <applet archive="cljapp.jar, clojure.jar" code="applet.class" width="400" height="200"></applet>
  </body>
</html>

Now you can upload the files "cljapp.html", "cljapp.jar" and "clojure.jar" to your webserver.

For signed applets only: When you open "cljapp.html" there, you will be asked (like every visitor of your website) if you trust the author of the applet. The applet can only be started when the user agrees.

Drawbacks[edit | edit source]

Some drawbacks of Clojure applets, compared to Java applets:

  • clojure.jar needs to be downloaded too, which has about 1.4 MB (you could try to use "clojure-slim.jar" instead which has only about 0.5 MB, but it seems not to work for unsigned applets)
  • For signed applets only: The applet is untrusted (unless you have an attested certificate from a certificate authority) and the users must agree to run it

Tips[edit | edit source]

  • Use "(set! *warn-on-reflection* true)" on the top of each file to find (and then eliminate) Reflection calls
  • Avoid "-main" methods! There seems to be an (open) bug in Clojure which lets the applets fail if there are "-main" methods. See this discussion

More example applets[edit | edit source]