Adding Applet as a Vaadin Component

Hello,

I have been trying for a while to add an Applet to my application as a Vaadin Component, but I have been unsuccessful in all my attempts.

So Far I have tried to use the embedded component to add the jar:

    Embedded embedded = new Embedded();
    embedded.setMimeType("application/x-java-applet");
    embedded.setType(Embedded.TYPE_OBJECT);
    embedded.setHeight("100%");
    embedded.setWidth("100%");
    embedded.setArchive("wave3D.jar");

where “wave3D.jar” is the jar that contains the applet. After setting the embedded component, I added it to the Application Window, but I can’t see the applet being displayed (either in Firefox, IE or Chrome).

I have also tried implementing the idea behind the Screenshot Widget Add-on as explained in this post “http://vaadin.com/forum/-/message_boards/message/119617?_19_redirect=/forum/-/message_boards/search%3F_19_redirect%3D%252Fforum%26_19_breadcrumbsCategoryId%3D0%26_19_searchCategoryIds%3D0%26_19_keywords%3Dapplet”.
However, I was still unable to figure out how to add the applet as a component to the application. I was able to use the screenshot add-on in my application with no problem, but using the screenshot widget add-on doesn’t add the applet to the application and found myself being stuck with my initial problem.

Has anyone successfully added an applet as a component to their Application or has some input on the topic?

Any ideas will be greatly appreciated,

Thanks.

Hi,

I took a look at this and you are absolutely right. The embedded (as per 6.3.3) does not support applets like that at all.
We need a ticket for this…

Anyway, I would have suggested using the AppletIntegration add-on, but I noticed it had some problems too. I fixed these and made the version 1.0.3 of the add-on available. Get it here:


http://vaadin.com/directory#addon/87

You use this by subclassing the AppletIntegration like this:

package com.example.applettest;

import java.util.Arrays;

import org.vaadin.applet.AppletIntegration;

public class MyApplet extends AppletIntegration {

    private static final long serialVersionUID = -4871198728412311481L;

    public MyApplet() {
        // Actual applet loaned from here: http://www.w3.org/People/mimasa/test/object/java/Othello
        setAppletArchives(Arrays.asList(new String[] { "Othello.jar" }));
        setCodebase("http://www.w3.org/People/mimasa/test/object/java/applets/");
        setAppletClass("Othello.class");
        setWidth("800px");
        setHeight("500px");
    }
}

Or, if you prefer less class files, here is how to make that inline:

        AppletIntegration applet = new AppletIntegration() {

            private static final long serialVersionUID = 1L;

            @Override
            public void attach() {
                // Actual applet loaned from here:
                // http://www.w3.org/People/mimasa/test/object/java/Othello
                setAppletArchives(Arrays.asList(new String[] { "Othello.jar" }));
                setCodebase("http://www.w3.org/People/mimasa/test/object/java/applets/");
                setAppletClass("Othello.class");
                setWidth("800px");
                setHeight("500px");

            }
        };
        mainWindow.addComponent(applet);

Great, thanks for responding. I actually found another way to solve this issue.

I got your applet-integration.jar and modified the VAppletIntegration.java file. More specifically I modified the getHTML() method since the width and height were hardcoded to be ‘0’. I modified so user can set them as attributes.

Here is the VAppletIntegration.java I am currently using. You will notice now how I added communication attributes for the height and the width. You will also note I added some extra parameters (e.g. window = opaque, mayscript) since i am noticing some problems with the z-order of embedded components (let that be applet, flash).

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.ui.HTML;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.ValueMap;

/**
 * Client side applet integration widget which communicates with the server.
 *
 *
 * @author Sami Ekblad
 *
 */
public class VAppletIntegration extends HTML implements Paintable {

    protected static final String PARAM_APP_SESSION = "appSession";
    protected static final String PARAM_APP_URL = "appUrl";
    protected static final String PARAM_APP_DEBUG = "appDebug";
    protected static final String PARAM_PAINTABLE_ID = "paintableId";
    protected static final String PARAM_APPLET_ID = "appletId";

    /** Client-server communication attributes. */
    public static final String ATTR_APPLET_SESSION = "appletSession";
    public static final String ATTR_APPLET_CLASS = "appletClass";
    public static final String ATTR_APPLET_ARCHIVES = "appletArchives";
    public static final String ATTR_APPLET_PARAM_NAMES = "appletParamNames";
    public static final String ATTR_APPLET_PARAM_VALUES = "appletParamValues";
    
    public static final String ATTR_APPLET_WIDTH = "appletWidth";
    public static final String ATTR_APPLET_HEIGHT = "appletHeight";
    
    public static final String ATTR_CMD = "cmd";
    public static final String ATTR_CMD_PARAMS = "cmdParams";

    /** Set the CSS class name to allow styling. */
    public static final String CLASSNAME = "v-applet";

    /** The client side widget identifier */
    protected String paintableId;

    /** Reference to the server connection object. */
    protected ApplicationConnection client;

    /** Generated applet id. Unique across the application. */
    private String appletId;

    /** Has the applet been initialized. Applet is initialized only once. */
    private boolean appletInitialized;
    private String appletClass;
    private String[] archives = new String[]
 {};
    private Map<String, String> appletParameters;
    private String appletSession;
    private int width;
    private int height;
    
    /**
     * The constructor should first call super() to initialize the component and
     * then handle any initialization relevant to Vaadin.
     */
    public VAppletIntegration() {

        // The content will be changed in update function
        setHTML("");

        // Temporary applet id. Should not be needed.
        appletId = CLASSNAME;

        // This method call of the Paintable interface sets the component
        // style name in DOM tree
        setStyleName(CLASSNAME);

    }

    /**
     * Called whenever an update is received from the server
     */
    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
        // This call should be made first.
        // It handles sizes, captions, tooltips, etc. automatically.
        if (client.updateComponent(this, uidl, true)) {
            // If client.updateComponent returns true there has been no changes
            // and we do not need to update anything.
            return;
        }

        // Save reference to server connection object to be able to send
        // user interaction later
        this.client = client;

        // Save the client side identifier (paintable id) for the widget
        paintableId = uidl.getId();

        appletId = CLASSNAME + paintableId;

        // Create the Java applet using HTML
        if (!appletInitialized) {

            // Applet class
            if (!uidl.hasAttribute(ATTR_APPLET_CLASS)) {
                ApplicationConnection.getConsole().log(
                        "Missing attribute " + ATTR_APPLET_CLASS);
                return;
            }
            appletClass = uidl.getStringAttribute(ATTR_APPLET_CLASS);
            
            width = uidl.getIntAttribute(ATTR_APPLET_WIDTH);
            height = uidl.getIntAttribute(ATTR_APPLET_HEIGHT);
            
            // Applet session
            if (!uidl.hasAttribute(ATTR_APPLET_SESSION)) {
                ApplicationConnection.getConsole().log(
                        "Missing attribute " + ATTR_APPLET_SESSION);
                return;
            }
            appletSession = uidl.getStringAttribute(ATTR_APPLET_SESSION);

            // Applet archives
            if (!uidl.hasAttribute(ATTR_APPLET_ARCHIVES)) {
                ApplicationConnection.getConsole().log(
                        "Missing attribute " + ATTR_APPLET_ARCHIVES);
                return;
            }
            archives = uidl.getStringArrayAttribute(ATTR_APPLET_ARCHIVES);

            // Applet appletParameters
            appletParameters = getDefaultIntegrationParameters();
            if (uidl.hasAttribute(ATTR_APPLET_PARAM_NAMES)) {
                ValueMap map = uidl.getMapAttribute(ATTR_APPLET_PARAM_NAMES);
                Set<String> keys = map.getKeySet();
                for (String key : keys) {
                    appletParameters.put(key, map.getString(key));
                }
            }

            // Create the HTML
            setHTML(getAppletHTML());
            appletInitialized = true;
        }

        // Execute the command
        String cmd = null;
        String[] cmdParams = null;
        if (uidl.hasAttribute(ATTR_CMD)) {
            cmd = uidl.getStringAttribute(ATTR_CMD);
        }
        if (uidl.hasAttribute(ATTR_CMD_PARAMS)) {
            cmdParams = uidl.getStringArrayAttribute(ATTR_CMD_PARAMS);
        }
        if (cmd != null) {
            execute(cmd, cmdParams);
        }

    }

    /**
     * Execute a command in applet using AbstractVaadinApplet.execute method.
     * Note that this requires that the applet has a method called "execute"
     *
     * @param cmd
     * @param cmdParams
     */
    public void execute(String cmd, String[] cmdParams) {
        ApplicationConnection.getConsole().log(
                "Applet command: " + getAppletId() + ",'" + cmd + "','"
                        + cmdParams + "'");
        if (cmdParams != null && cmdParams.length > 0) {
            internalAppletExecute(getAppletId(), cmd, cmdParams);
        } else {
            internalAppletExecute(getAppletId(), cmd);
        }
    }

    /**
     * This is the internal method that invokes the execute method in applet.
     * Note that this requires that the applet has a method called "execute"
     *
     * @param id
     * @param cmd
     */
    private native void internalAppletExecute(String id, String cmd)
    /*-{
       if ($doc.applets[id]
) {
            $doc.applets[id]
.execute(cmd);
        }
    }-*/;

    /**
     * This is the internal method that invokes the execute method in applet.
     * Note that this requires that the applet has a method called "execute"
     * with string parameters.
     *
     * @param id
     * @param cmd
     * @param cmdParams
     */
    private native void internalAppletExecute(String id, String cmd,
            String[] cmdParams)
    /*-{
       if ($doc.applets[id]
) {
            $doc.applets[id]
.execute(cmd,cmdParams);
        }
    }-*/;

    /**
     * Get paintable id of this widget.
     *
     * @return
     */
    protected String getPaintableId() {
        return paintableId;
    }

    /**
     * Get applet HTML needed to initalize applet.
     *
     * Note: the default implementation does not return anything.
     *
     * @return String containing the APPLET tag needed to initialize the Java
     *         applet.
     */
    protected String getAppletHTML() {

        // Compose dependency JAR files
        List<String> archives = getArchives();
        String archiveAttribute = "";
        if (archives != null) {
            boolean first = true;
            for (String a : archives) {
                if (!first) {
                    archiveAttribute += ",";
                } else {
                    first = false;
                }
                archiveAttribute += a;
            }
        }

        // Compose applet appletParameters
        Map<String, String> appletParams = getAppletParameters();
        String appletParamStr = "";
        if (appletParams != null) {
            for (String name : appletParams.keySet()) {
                appletParamStr += "<param name=\"" + name + "\" value=\""
                        + appletParams.get(name) + "\" />";
            }
        }
        appletParamStr += "<param name=\"" + "wmode" + "\" value=\""
        + "opaque" + "\" />";

        String myscript = "<param name=\"mayscript\" value=\"yes\">";
		String scriptable = "<param name=\"scriptable\" value=\"true\">";
		
        return "<applet mayscript=\"true\" code=\"" + "" + getAppletClass()
                + "" + "\" codebase=\"" + GWT.getModuleBaseURL()
                + "\" width=\"" + width + "\" height=\"" + height + "\" id=\"" + getAppletId()
                + "\" name=\"" + getAppletId() + "\" archive=\""
                + archiveAttribute + "\">" + appletParamStr +  myscript + scriptable + "</applet>";
    }

    /**
     * Get appletParameters for the applet as a Map.
     *
     * @return
     */
    protected Map<String, String> getAppletParameters() {
        return appletParameters;
    }

    /**
     * Get id for this applet.
     *
     * @return
     */
    protected String getAppletId() {
        return appletId;
    }

    /**
     * Get list of archives needed to run the applet.
     *
     * @return
     */
    protected List<String> getArchives() {
        ArrayList<String> res = new ArrayList<String>();
        for (int i = 0; i < archives.length; i++) {
            res.add(archives[i]
);
        }
        return res;
    }

    /**
     * Get name of the applet class.
     *
     * @return
     */
    protected String getAppletClass() {
        return appletClass;
    }

    /**
     * Get default appletParameters for the applet.
     *
     * @return
     */
    private Map<String, String> getDefaultIntegrationParameters() {
        Map<String, String> res = new HashMap<String, String>();

        // Add default appletParameters
        res.put(PARAM_APPLET_ID, "" + getAppletId());
        res.put(PARAM_PAINTABLE_ID, "" + getPaintableId());

        String sessionId = appletSession;
        if (sessionId == null) {
            sessionId = Cookies.getCookie("JSESSIONID");
        }
        res.put(PARAM_APP_SESSION, "JSESSIONID=" + sessionId);
        res.put(PARAM_APP_DEBUG, ApplicationConnection.isDebugMode() ? "true"
                : "false");
        res.put(PARAM_APP_URL, GWT.getHostPageBaseURL() + client.getAppUri());

        return res;
    }

}

Now all you have to do is set the attributes yourself, like in the code below, and you will notice the applet embedded within your application.
I believe your appletintegration.jar was doing things right, except for the little detail of height/width being harcoded to ‘0’, which obviously made the applet not appear in the application.


        target.addAttribute(VAppletIntegration.ATTR_APPLET_WIDTH,800);
        target.addAttribute(VAppletIntegration.ATTR_APPLET_HEIGHT, 600);

Looks good and you are right. That is the way it was designed: to provide custom applet at the client-side.

I think that it would be good to have this possible using the server side API too and the size was just. Thats why I added the codebase and width and height.

Your addition to height and width are identical to version 1.0.3, but the mayscript is attribute instead of parameter. Is it required as param by some browsers? A generic way of adding params would be nice.

I put the mayscript parameter since I am looking for a way to receive events from the applet. Using your strategy for the screenshot tool, I was able to send events from vaadin to the applet. I also want the applet to be able to send events to Vaadin, so I added the parameter since It appears to be “required when you will be manipulating the applet via Web page scripting or will be triggering Web page scripting from an applet event such as clicking…”.

Have you been able to send events from the applet to vaadin? The approach I am taking is to call the javascript methods directly from the applet using the JSObject class.

The JSObject class allows you to get the Window containing the applet. From there you can use the class method call(String arg0, string arg1)". This allows you to call Javascript methods directly from the applet, but the problem I am facing now is that the names I give to the methods when coding in Java are changed once Vaadin compiles the project and translates them to Javascript. Therefore, calling the Javascript methods is a pain since the methods are named generically instead of keeping the names that were given to them in the java code.

Right, the client-side part is compiled with GWT so the JavaScript functions are obfuscated. There is no way around that other than registering them using JSNI into window object. Quickly found this sample about this:
http://googlewebtoolkit.blogspot.com/2008/07/getting-to-really-know-gwt-part-1-jsni.html

For those who only need to pass something to the server-side the
AppletIntegration
already helps with this. If you can create your applet by extending the
AbstractVaadinApplet
. Just use the vaadinUpdateVariable method.

Hi,
Is it possible to transfer data objects between applet and server in both direction?

Hi,
Iam trying to add my applet to vaadin application…but failed…getting class format exception…please send me where i have to place my applet class file in our project and jar which contains the applet class…
its too urgent…plz send me one full application which contains vaadin application with applet class file and and the jar file which contains our custom applet