Since Java 6 update 10 Sun released the
Deployment Toolkit.
This kit is a Javascript file
that can generate the required HTML to deploy Java applets
and Web Start applications. The good thing is the script will take care of
all odities between browsers, the applet
and embed
tags. And we can make sure the minimal Java version for our applet is
available on the client's machine. If the required Java version is not
available it will be downloaded and installed on the computer.
In this post we see a Wicket component which will replace an
applet
tag with Javascript. Attributes set for the
applet
tag are passed on to the Javascript. If we use another
HTML element to be replaced, we must programmatically set all attributes.
Let's start with a sample page with the applet
tag and a
div
tag. These tags are replaced with Javascript code by the
Wicket component.
<html> <head> </head> <body> <applet wicket:id="applet" code="Applet.class" archive="applet.jar" width="100" height="200"/> <div wicket:id="appletDiv"/> </body> </html>
We create our Wicket component by extending the
org.apache.wicket.markup.html.WebComponent
. We then override
the onComponentTag
and onComponentTagBody
methods:
package com.mrhaki.wicket.components; import org.apache.wicket.markup.html.WebComponent; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.MarkupStream; public class DeployJava extends WebComponent { private static final long serialVersionUID = 1L; public DeployJava(final String id) { super(id); } @Override protected void onComponentTag(final ComponentTag tag) { super.onComponentTag(tag); tag.setName("script"); } @Override protected void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) { final StringBuilder script = new StringBuilder(); replaceComponentTagBody(markupStream, openTag, script.toString()); } }
This code doesn't do much yet. The only thing we have achieved is that the
component will render a script
tag with no content. Now it is time
to add more functionality. We want to be able to render Javascript like this:
<script> var attributes = { code: 'Applet.class', archive: 'applet.jar', width: 100, height: 200 }; var parameters = { text: 'Hello world' }; var version = "1.6"; javaDeploy.runApplet(attributes, parameters, version); </script>
So we start by adding properties in our component to store attributes,
parameters and version text. Next we can implement the code in
onComponentTagBody
to output the Javascript:
... import net.sf.json.JSONObject; import org.apache.wicket.util.value.IValueMap; import org.apache.wicket.util.value.ValueMap; ... private String minimalVersion; private IValueMap appletAttributes = new ValueMap(); private IValueMap appletParameters = new ValueMap(); ... @Override protected void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) { final StringBuilder script = new StringBuilder(); if (appletAttributes.size() > 0) { final JSONObject jsonAttributes = JSONObject.fromObject(appletAttributes); script.append("var attributes = " + jsonAttributes + ";"); } else { script.append("var attributes = {};"); } if (appletParameters.size() > 0) { final JSONObject jsonParameters = JSONObject.fromObject(appletParameters); script.append("var parameters = " + jsonParameters + ";"); } else { script.append("var parameters = {};"); } if (minimalVersion != null) { script.append("var version = \"" + minimalVersion + "\";"); } else { script.append("var version = null;"); } script.append("deployJava.runApplet(attributes, parameters, version);"); replaceComponentTagBody(markupStream, openTag, script.toString()); } ... public void setMinimalVersion(final String minimalVersion) { this.minimalVersion = minimalVersion; } public void addParameter(final String key, final Object value) { appletParameters.put(key, value); } public void addAttributes(final String key, final Object value) { appletAttributes.put(key, value); } ...
We use the JSON-lib library to convert the attributes and parameters map to Javascript. We also add methods to set values for the properties.
Okay, the component displays the correct Javascript, but we need to add
a reference to the Deployment Toolkit Javascript file, otherwise the method
deployJava.runApplet
is not recognized. We extend the Wicket
component and implement the org.apache.wicket.markup.html.IHeaderContributor
interface. Wicket components that implement this interface must implement
the method renderHead
. Wicket will invoke this method and add
a Javascript reference in the HTML head section of our web page.
For now we simply add a reference to http://java.com/js/deployJava.js.
import org.apache.wicket.markup.html.IHeaderResponse; public class DeployJava extends WebComponent implements IHeaderContributor { public void renderHead(IHeaderResponse response) { response.renderJavascriptReference("http://java.com/js/deployJava.js"); } }
And that is it for a basic component which renders the correct
Javascript. The following code shows a complete component, which
can read attributes set on the applet
tag and use them
in the Javascript. We can also choose between adding the Javascript
source file as a Wicket resource or as a reference
to the public Sun website URL.
package com.mrhaki.wicket.components; import net.sf.json.JSONObject; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.MarkupStream; import org.apache.wicket.markup.html.IHeaderContributor; import org.apache.wicket.markup.html.IHeaderResponse; import org.apache.wicket.markup.html.WebComponent; import org.apache.wicket.markup.html.resources.CompressedResourceReference; import org.apache.wicket.util.value.IValueMap; import org.apache.wicket.util.value.ValueMap; /** * <p>Wicket component to add the * <a href="http://java.sun.com/javase/6/docs/technotes/guides/jweb/deployment_advice.html">Sun's Deployment Toolkit</a> * Javascript. * The markup can be defined as applet. Attributes defined for the applet are * copied to the Javascript. The markup can also be another element, for example * a div element.</p> * <p> * Suppose we have the following applet markup: * <pre> * <applet wicket:id="applet" width=200 height=120 code="SignatureApplet.class" * archive="codesign.jar"></applet> * </pre> * In a Wicket page we can create this component and add it to the page: * <pre> * final JavaDeploy javaDeploy = new JavaDeploy("applet"); * add(javaDeploy); * </pre> * We get the following output: * <pre> * <html> * <head> * <script type="text/Javascript" src="http://java.com/js/deployJava.js"></script> * </head> * <body> * <script> * var attributes = { "width":200,"height":120,"code":"SignatureApplet.class","archive":"codesign.jar"}; * var parameters = {}; * var version = null; * deployJava.runApplet(attributes, parameters, version); * </script> * </body> * </html> * </pre> * </p> */ public class DeployJava extends WebComponent implements IHeaderContributor { private static final long serialVersionUID = 1L; /** * Javascript URL on Sun's website for deployJava Javascript. (={@value}) */ private static final String JAVASCRIPT_URL = "http://java.com/js/deployJava.js"; /** * Attribute to set the width of the applet. (={@value}) */ private static final String ATTRIBUTE_WIDTH = "width"; /** * Attribute to set the height of the applet. (={@value}) */ private static final String ATTRIBUTE_HEIGHT = "height"; /** * Attribute to set the applet classname. (={@value}) */ private static final String ATTRIBUTE_CODE = "code"; /** * Attribute to set the codebase for the applet. (={@value}) */ private static final String ATTRIBUTE_CODEBASE = "codebase"; /** * Attribute to set the archive neede by the applet. (={@value}) */ private static final String ATTRIBUTE_ARCHIVE = "archive"; /** * Minimal Java version needed for the applet. */ private String minimalVersion; /** * If true we use a local resource otherwise the URL from the Sun site. * For the local resource we must add the file deployJava.js next to * this class in our package structure. */ private boolean useJavascriptResource; /** * Attributes for the javaDeploy.runApplet Javascript method. */ private IValueMap appletAttributes = new ValueMap(); /** * Parameters for the javaDeploy.runApplet Javascript method. */ private IValueMap appletParameters = new ValueMap(); /** * Default constructor with markup id. * * @param id Markup id for applet. */ public DeployJava(String id) { super(id); } /** * Minimal Java version for the applet. E.g. Java 1.6 is "1.6". * * @param version Minimal Java version needed by the applet. */ public void setMinimalVersion(final String version) { this.minimalVersion = version; } /** * Width of the applet. * * @param width Width of the applet on screen. */ public void setWidth(final Integer width) { appletAttributes.put(ATTRIBUTE_WIDTH, width); } /** * Height of the applet. * * @param height Height of the applet on screen. */ public void setHeight(final Integer height) { appletAttributes.put(ATTRIBUTE_HEIGHT, height); } /** * Applet classname. * * @param code Applet classname. */ public void setCode(final String code) { appletAttributes.put(ATTRIBUTE_CODE, code); } /** * Codebase for the applet code. * * @param codebase Codebase for the applet code. */ public void setCodebase(final String codebase) { appletAttributes.put(ATTRIBUTE_CODEBASE, codebase); } /** * Archive path for the applet. * * @param archive Archive location for the applet. */ public void setArchive(final String archive) { appletAttributes.put(ATTRIBUTE_ARCHIVE, archive); } /** * Add a parameter to the applet. * * @param key Name of the parameter. * @param value Value for the parameter. */ public void addParameter(final String key, final Object value) { appletParameters.put(key, value); } /** * Indicate if deployJava Javascript must be loaded from the Sun site or as local resource. * * @param useResource True local resource is used, otherwise Sun site. */ public void setUseJavascriptResource(final boolean useResource) { this.useJavascriptResource = useResource; } /** * Get the applet attributes already set and assign them to the attribute * list for the Javascript code. And we change the tag name to "script". * * @param tag De current tag which is replaced. */ @Override protected void onComponentTag(ComponentTag tag) { super.onComponentTag(tag); if ("applet".equalsIgnoreCase(tag.getName())) { final IValueMap tagAttributes = tag.getAttributes(); // Save wicket:id so we can add again to the list of attributes. final String wicketId = tagAttributes.getString("wicket:id"); appletAttributes.putAll(tagAttributes); tagAttributes.clear(); tagAttributes.put("wicket:id", wicketId); } tag.setName("script"); } /** * Create Javascript for deployJava.runApplet. * * @param markupStream MarkupStream to be replaced. * @param openTag Tag we are replacing. */ @Override protected void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) { final StringBuilder script = new StringBuilder(); if (appletAttributes.size() > 0) { final JSONObject jsonAttributes = JSONObject.fromObject(appletAttributes); script.append("var attributes = " + jsonAttributes + ";"); } else { script.append("var attributes = {};"); } if (appletParameters.size() > 0) { final JSONObject jsonParameters = JSONObject.fromObject(appletParameters); script.append("var parameters = " + jsonParameters + ";"); } else { script.append("var parameters = {};"); } if (minimalVersion != null) { script.append("var version = \"" + minimalVersion + "\";"); } else { script.append("var version = null;"); } script.append("deployJava.runApplet(attributes, parameters, version);"); replaceComponentTagBody(markupStream, openTag, script.toString()); } /** * Add Javascript src reference in the HTML head section of the web page. * * @param response Header response. */ public void renderHead(IHeaderResponse response) { if (useJavascriptResource) { response.renderJavascriptReference(new CompressedResourceReference(JavaDeploy.class, "deployJava.js")); } else { response.renderJavascriptReference(JAVASCRIPT_URL); } } }
If we look at the beginning of the post we see the HTML for a web page. We create the code for the page as follows:
package com.mrhaki.wicket.page; public class AppletPage extends WebPage { public AppletPage() { final DeployJava applet = new DeployJava("applet"); add(applet); final DeployJava div = new DeployJava("appletDiv"); div.setWidth(100); div.setHeight(200); div.setCode("NewApplet.class"); div.setCodeBase("../classes"); div.addParameter("text", "Hello world"); div.setMinimalVersion("1.6"); add(div); } }
When we run the page we get the following HTML:
<html> <head> <script type="text/javascript" src="http://java.com/js/deployJava.js"></script> </head> <body> <script> var attributes = { "code":"Applet.class", "archive":"applet.jar", "width":100, "height":200 }; var parameters = {}; var version = null; deployJava.runApplet(attributes, parameters, version); </script> <script> var attributes = { "code":"NewApplet.class", "codebaSE":"../classes", "width":100, "height":200 }; var parameters = { "text":"Hello world" }; var version = "1.6"; deployJava.runApplet(attributes, parameters, version); </script> </body> </html>