Applet integration

Hi Sami,

Do you know, why this add-on not supported Safari v5 and Google Chrome browsers?

After calling server side method “executeCommand”, applet side method “doExecute” never is called. Why?

Thanks,
Michael

I just haven’t taken look what is needed for the webkit based browsers to get applets running. I guess that there may be some differences in the Java-JS bridge implementation at least. Currently this is multithreaded to make applet privileges to work.

Any help investigating this is very much appreciated.

Hi Sami,

We made a workaround to be able to make AppletIntegration work on Safari & Chrome. Instead of executing applet commands from doExecute method via executeCommand we used setAppletParams on the server side & moved all logic from doExecute method to method run() wich is called from applet’s start() method. The call to run is as follows:

@Override
    public void start()
    {
        ...
        run(getParameter("mode"));

    }

Applet parameter is set in attach() method:

@Override
                public void attach() {

                    setAppletArchives(Arrays.asList(APPLET_ARCHIVES));
                    setCodebase("VAADIN/applets/");
                    setAppletClass(APPLET_CLASS);
                    setAppletParams("mode", mode);
                }

This works fine for Firefox, Safari & Chrome, but doesn’t work good on IE. The problem is that after running applet on IE Out of sync error always appears with the following log message: SEVERE: Warning: Ignoring variable change for non-existent component, VAR_PID=PID15. We use changeVariables method on server side & vaadinUpdateVariable from applet to update variables values from client side. Could you please advise what can cause Out of sync problem in this case (only on IE)?

Thanks,
Alexander

This could be an application-level problem. The OOS comes when client tries to send a variable for a component that has been already removed from the server-side.

I tried to find out what component causes OOS warning & according to debug information it was some component inside AppletIntegration. Could you please tell is there any possibility to exactly find out what component has PID that is specified in OOS warning or how to get component PID from the code?

There should not be anything “inside” the AppletIntegration, so it must the the component itself.

The PID is assigned by the communication servlet and I think there is n easy way of getting it in your application. You can set the debugId for the component to force the id to be something. Like comp.setDebugId(“something”) then the variable will have the name “PID_something”.

However, if it is only IE causing this it might be completely something else. It might be a delay when applet sends something back (i.e. calls js) or double-post situation or something…

I’m sorry I cannot figure out what could it be without seeing, but I’ll post here if I come up with some more debugging ideas.

I developed a workaround for this IE problem & found other interesting fact: I created another thread that is started when applet is needed to be removed from layout, in this thread applet is detached & removed after some delay (about 5 seconds) to be sure that all requests are already sent & received. In this case applet works fine, after it is removed from the layout & switching to another layout no out of sync warning appears. But when I try to perform any action in new layout (e.g. button press or tree expand) I get this warning with debug id that I assigned to AppletIntegration component. Even if a lot of time passed since applet was removed. Also I stopped applet manually from the inside calling System.exit from applet class, but the result is the same. May be you can give some explanation to this strange behavior.

Strange indeed. Sounds like there is some event sent during the client-side detach that is reflected back to the server a bit too late. Why it is only on IE? Probably because of some GWT behavior or because of a delay when removing applets from DOM. Anyway, I’m pretty sure this can be fixed in the client-side VApplicatIntegration somehow…

Hello All,

Is it possible to use arbitrary applet via AppletIntegration add-on, or it should be an applet, subclassed from AbstractApplet ?

Is just subclassing AppletIntegration and setting jar details sufficient to use it as Vaadin component ? The reason for asking is using a subclass of AppletIntegration (and adding maven dependency on the add-on) gives the following error:

"Widgetset does not contain implementation for org.vaadin.applet.AppletIntegration. Check its @ClientWidget mapping, widgetsets GWT module description file and re-compile your widgetset. In case you have downloaded a vaadin add-on package, you might want to refer to add-on instructions. Unrendered UIDL:

org.vaadin.applet.AppletIntegration(NO CLIENT IMPLEMENTATION FOUND)"

Obviously, the configuration of client widget (VApletIntegration) is missing. Could you please point to example or documentation how to include it?

Please excuse me if this was already answered elsewhere.

It is possible. The AbstractApplet just implements the communication between Vaadin so that you don’t have to worry about the details. If you don’t need that you can use different applet class altogether.

You still have to compile the widgetset once to get the thing working. That what you are missing here. Take a look at instructions here:
http://vaadin.com/directory/help/using-vaadin-add-ons

Unfortunately I don’t have extensive documentation available currently, but now that I have some clear use-cases I could set up a wiki page or something to answer the most important questions.

Thank you, mvn vaadin:update-widgetset install was indeed what was missing.

Once the widgetset is compiled, and not going to be changed is it sufficient to copy them into VAADIN/widgetsets folder and switch off the GWT compilation?

And one more question - it seems the applet integration component shows nothing if embedded in a popup window ? (which is reasonable to expect if popup windows are overlays).

Sorry, another question - do I understand right , there is no easy way to client side scripting (e.g. invoke arbitrary applet method and change a text field) ?

Vaadin works mainly at the server-side and that is where the application control should be.

With applets you can call back to server using the AbstractVaadinApplet.vaadinUpdateVariable and catch that in the

There is also a way to call arbitrary JavaScript using the jsCallAsync and jsCallSync methods in the AbstractVaadinApplet.

If you wish to send something to the applet you should use the executeCommand in AppletIntegration (server-side) component. That can be handled in you applet by implementing the abstract doExecute method.

Currently there is no support for calling arbitraty applet methods from the server, but maybe that would make sense too.

About the problem with subwindow: I would have thought it works, but maybe browsers somehow prevent the z-indexing of applets properly.

Hello,

I have developed a project in which 3D graphics rendering is possible in the web browser using a combination of Vaadin , JMonkeyEngine game platform, ICEPush and the AppletIntegration add-on.

You can see an online demo
here

Vaadin was used to create the main application and user interface. The AppletIntegration add-on was used to add the applet to the Vaadin Application. Inside my main applet class which extended “AbstractVaadinApplet” (provided on AppletIntegration add-on) , I added the code to be able to render 3D graphics inside the Java Applet using the JMonkeyEngine game Engine. The communication between vaadin and the Applet was done through the mechanism offered in this Add-on along with a combination of the mechanism offered by the ICEPush add-on found in the Vaadin Add-on repository.

I have created a google code project in which I committed the code used for the online demo as well as the code used to create the 3D graphics in the applet.

You can check it out at
the jmonkeyengine-vaadin-integration google code web site

You can also visit the
Whole Brain Catalog
web application,a 3D Neuroscience tool, which makes use of this strategy and is more developed than the online demo provided above.

So far it works well in Windows (Firefox, Chrome, IE, Opera), Mac (Firefox, Safari 4).

The AppletIntegration seems to be having problems in Safari 5, the doExecute() method receives null parameters even though the Vaadin application sends the Applet non-null parameters. The issue is also reproduced in Firefox and Chrome in Ubuntu Linux.

Hi! As an old fan of the
jMonkeyEngine
I’d say that you have a very interesting project there :slight_smile:

What you say about the disappearing applet parameters, I have to take a look. Effectively, it is a JavaScript call to document.applets[ID]
.execute(name, params), but maybe there is something different between the browsers. Although, I must say this use case hasn’t been too extensively tested in my applications…

Btw: the setup seems fails to install the native ljwgl libraries under OS X.

Thanks for letting me know it fails to install the libraries, I just fix this for the online demo and should work this time around.

I also created a video demonstrating the interaction between vaadin and jme.
Demo Video

Hello :slight_smile:

I’m trying to use AppletIntegration with Vaadin 6.53 but I can’t make it work.

I need to send image to server-side from applet and then get it back to vaadin application, like you do in Screenshot add-on. I tried to run Screenshot demo but it doesn’t work for me and in Java Console I have:

security: resource name “org/apache/commons/httpclient/methods/multipart/PartSource.class” in http://sami.virtuallypreinstalled.com/screenshot/VAADIN/widgetsets/org.vaadin.screenshot.widgetset.ScreenshotApplicationWidgetset/commons-httpclient-3.1.jar : java.lang.SecurityException: trusted loader attempted to load sandboxed resource from http://sami.virtuallypreinstalled.com/screenshot/VAADIN/widgetsets/org.vaadin.screenshot.widgetset.ScreenshotApplicationWidgetset/commons-httpclient-3.1.jar
Exception in thread “AWT-EventQueue-2” java.lang.SecurityException: trusted loader attempted to load sandboxed resource from http://sami.virtuallypreinstalled.com/screenshot/VAADIN/widgetsets/org.vaadin.screenshot.widgetset.ScreenshotApplicationWidgetset/commons-httpclient-3.1.jar
at com.sun.deploy.security.CPCallbackHandler$ParentCallback.check(Unknown Source)
at com.sun.deploy.security.CPCallbackHandler$ParentCallback.access$1500(Unknown Source)
at com.sun.deploy.security.CPCallbackHandler$ChildElement.checkResource(Unknown Source)
at com.sun.deploy.security.DeployURLClassPath$JarLoader.checkResource(Unknown Source)
at com.sun.deploy.security.DeployURLClassPath$JarLoader.getResource(Unknown Source)
at com.sun.deploy.security.DeployURLClassPath.getResource(Unknown Source)

I supposed this is because signing issues so I toked the source and signed this jar, but again there was no success.

In server log I have got:

10:41:31,504 ERROR [STDERR]
18.03.2011. 10.41.31 com.vaadin.terminal.gwt.server.AbstractApplicationServlet serveStaticResourcesInVAADIN
[exec]
INFO: Requested resource [VAADIN/widgetsets/com.ecsmon.scanapplet.widgetset.EcsscanappletWidgetset/META-INF/services/org.apache.commons.logging.LogFactory]
not found from filesystem or through class loader. Add widgetset and/or theme JAR to your classpath or add files to WebContent/VAADIN folder.
[exec]
10:41:31,622 ERROR [STDERR]
18.03.2011. 10.41.31 com.vaadin.terminal.gwt.server.AbstractApplicationServlet serveStaticResourcesInVAADIN
[exec]
INFO: Requested resource [VAADIN/widgetsets/com.ecsmon.scanapplet.widgetset.EcsscanappletWidgetset/org/apache/log4j/Category.class]
not found from filesystem or through class loader. Add widgetset and/or theme JAR to your classpath or add files to WebContent/VAADIN folder.

and from Java Console I can see that PID and SID are OK such as postUrl http://localhost:8080//app_name

I tried to add missing files (“META-INF/services/org.apache.commons.logging.LogFactory” , “org/apache/log4j/Category.class” ) manually but it keeps giving me same result.

Because Screenshot extends Upload I was reading source of Upload component and I saw there is no “stream” variable which was called from Screenshot paintContent method (target.addUploadStreamVariable(this, “stream”);), and then I realized that in Vaadin 6.53 Upload component have different implementation then Vaadin 6.24. Because of that I tried like this:

public void paintContent(PaintTarget target) throws PaintException {

		super.paintContent(target);

	//      target.addUploadStreamVariable(this, "stream");
	//	target.addVariable(this, "action", getStreamVariable());
	// Because we don't inherit the AppletIntegration component on the
	// server-side, we have to add the attributes explicitly here:
	String sid = getHttpSessionId();
	if (sid != null) {
		target.addAttribute(VAppletIntegration.ATTR_APPLET_SESSION, sid);
	}
	target.addAttribute(VAppletIntegration.ATTR_APPLET_CLASS, APPLET_CLASS);
	target.addAttribute(VAppletIntegration.ATTR_APPLET_ARCHIVES, APPLET_ARCHIVES);
	target.addAttribute(VAppletIntegration.ATTR_APPLET_PARAM_NAMES, APPLET_ARCHIVES);
	if (screenshot) {
		target.addAttribute(VAppletIntegration.ATTR_CMD, CMD_SCAN);
		screenshot= false;
	}
}

but it doesn’t work again.
Then I used firebug to see what happens when uploading files and in response I got something like this:

for(;;);[{“changes”:[[“change”,{“format”: “uidl”,“pid”: “PID167”},[“14”,{“id”: “PID167”,“width”: “100.0%”},“Uploaded file contained 716 linebreaks”]
],[“change”,{“format”: “uidl”,“pid”: “PID166”},[“15”,{“id”: “PID166”,“caption”: “Upload a file”,“tabindex”:0,“state”:false,“buttoncaption”: “Upload”,“nextid”:1,“v”:{“action”:“http://localhost:8080/app_name/APP/UPLOAD/PID166/action/6b9ee76f-b43f-4a8e-995b-e8a3356ad07f”}}]
]], “meta” : {}, “resources” : {}, “locales”:}]

so I conclude that http://licalhost:8080/app_name/APP/UPLOAD/PID166/action/6b9ee76f-b43f-4a8e-995b-e8a3356ad07f is postUrl (am I wrong?) Here I’m stacked :slight_smile:

Basically I need applet to do same thing as upload but with file (in this case image ) that is generated with applet and that file needs to be somehow displayed in vaadin application.
What am I missing?
Is there another way to do this in latest version of Vaadin, or there is another add-on or something?

Sorry for bad English :slight_smile:

Thanks in advance!

Hello everyone :slight_smile:

I have found the solution. I modified VAppletIntegration, AbstractVaadinApplet and paintContent method from ScreenShot. Here are modifications:

VAppletIntegration:

-aded fields:
– protected static final String PARAM_ACTION = “action”;
– public static final String ATTR_APPLET_ACTION = “action”;
– private String action;
-updateFromUIDL(…)
– if(uidl.hasVariable(ATTR_APPLET_ACTION)){
action = uidl.getStringVariable(ATTR_APPLET_ACTION);
}
-private Map<String, String> getDefaultIntegrationParameters()
– added line res.put(PARAM_ACTION,action);


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";
    protected static final String PARAM_ACTION = "action";  //this is added

	/** 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_CODEBASE = "appletCodebase";
	public static final String ATTR_APPLET_ACTION = "action";  //this is added

	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 String height = "0";
	private String width = "0";
	private String codebase;
	private String action;  //this is added
	/**
	 * 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;

		// Export client reference for applet use
		exportClientUpdateVariable(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)) {
				VConsole.log("Missing attribute " + ATTR_APPLET_CLASS);
				return;
			}
			appletClass = uidl.getStringAttribute(ATTR_APPLET_CLASS);

			// Applet session
			if (!uidl.hasAttribute(ATTR_APPLET_SESSION)) {
				VConsole.log("Missing attribute " + ATTR_APPLET_SESSION);
				return;
			}
			appletSession = uidl.getStringAttribute(ATTR_APPLET_SESSION);

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

			// Allow overriding of the default codebase
			if (uidl.hasAttribute(ATTR_APPLET_CODEBASE)) {
				codebase = uidl.getStringAttribute(ATTR_APPLET_CODEBASE);
			}

			// Width and height if provided
			if (uidl.hasAttribute("width")) {
				setWidth(uidl.getStringAttribute("width"));
			} else {
				setWidth("0");
			}

			if (uidl.hasAttribute("height")) {
				setHeight(uidl.getStringAttribute("height"));
			} else {
				setHeight("0");
			}

			 //this is added
			if(uidl.hasVariable(ATTR_APPLET_ACTION)){
				action = uidl.getStringVariable(ATTR_APPLET_ACTION);
			}

			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);
		}
	}

	private native static void exportClientUpdateVariable(ApplicationConnection client) 
	/*-{
		var c = client;
		$wnd.vaadin.appletUpdateBooleanVariable = function(pid, variableName, newValue, immediate) {
		c.@com.vaadin.terminal.gwt.client.ApplicationConnection::updateVariable(Ljava/lang/String;Ljava/lang/String;ZZ)(pid, variableName, newValue, immediate);
		};
		$wnd.vaadin.appletUpdateIntVariable = function(pid, variableName, newValue, immediate) {
		c.@com.vaadin.terminal.gwt.client.ApplicationConnection::updateVariable(Ljava/lang/String;Ljava/lang/String;IZ)(pid, variableName, newValue, immediate);
		};
		$wnd.vaadin.appletUpdateDoubleVariable = function(pid, variableName, newValue, immediate) {
		c.@com.vaadin.terminal.gwt.client.ApplicationConnection::updateVariable(Ljava/lang/String;Ljava/lang/String;DZ)(pid, variableName, newValue, immediate);
		};
		$wnd.vaadin.appletUpdateStringVariable = function(pid, variableName, newValue, immediate) {
		c.@com.vaadin.terminal.gwt.client.ApplicationConnection::updateVariable(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)(pid, variableName, newValue, immediate);
		};
	}-*/;

	/**
	 * 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) {
		VConsole.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) + "\" />";
			}
		}
		return "<applet mayscript=\"true\" code=\"" + "" + getAppletClass() + "" + "\" codebase=\"" + getCodebase() + "\" width=\"" + getWidth() + "\" height=\"" + getHeight() + "\" id=\"" + getAppletId() + "\" name=\"" + getAppletId() + "\" archive=\"" + archiveAttribute + "\">" + appletParamStr + "</applet>";
	}

	/**
	 * Get codebase of this applet. By default the code base points to
	 * GWT.getModuleBaseURL().
	 * 
	 * @return
	 */
	private String getCodebase() {
		return codebase == null ? GWT.getModuleBaseURL() : codebase;
	}

	protected String getHeight() {
		return height;
	}

	protected String getWidth() {
		return width;
	}

	@Override
	public void setWidth(String w) {
		super.setWidth(w);
		width = w;
	}

	@Override
	public void setHeight(String h) {
		super.setHeight(h);
		height = h;
	}

	public String getAction() {
		return action;
	}

	public void setAction(String action) {
		this.action = action;
	}

	/**
	 * 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, ApplicationConfiguration.isDebugMode() ? "true" : "false");
		res.put(PARAM_APP_URL, GWT.getHostPageBaseURL() + client.getAppUri());
		res.put(PARAM_ACTION,action);  //this is added
		return res;
	}

}

AbstractVaadinApplet:

  • fields added
    – protected static final String PARAM_ACTION = “action”;
    – private String action; - added getter and setter for this field
  • init() method added line setAction(getParameter(PARAM_ACTION));

public abstract class AbstractVaadinApplet extends Applet {

    private static final long serialVersionUID = -1091104541127400420L;

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


    protected static long MAX_JS_WAIT_TIME = 10000;

    private boolean debug = false;

    private JsPollerThread pollerThread;

    private Object pollerLock = new Object[] {};

    public boolean runPoller = true;

    private String applicationURL;

    private String sessionCookie;

    private String paintableId;

    private String appletId;
    
    private String action;

    @Override
    public void init() {
        setDebug("true".equals(getParameter(PARAM_APP_DEBUG)));
        setAppletId(getParameter(PARAM_APPLET_ID));
        setPaintableId(getParameter(PARAM_PAINTABLE_ID));
        setApplicationURL(getParameter(PARAM_APP_URL));
        setApplicationSessionCookie(getParameter(PARAM_APP_SESSION));
        setAction(getParameter(PARAM_ACTION));
        // Start the poller thread for JS commands
        pollerThread = new JsPollerThread();
        pollerThread.start();
    }

    /**
     * Set the id of the applet in DOM.
     *
     * @param paintableId
     */
    private void setAppletId(String appletId) {
        this.appletId = appletId;
        debug("appletId=" + appletId);
    }

    /**
     * Get the id of the applet in DOM.
     *
     * @return The id of this applet in the Vaadin application DOM document.
     */
    protected String getAppleteId() {
        return appletId;
    }

    /**
     * Set the paintable id of the applet widget.
     *
     * @param paintableId
     *            The id of this applet widget in the Vaadin application.
     */
    private void setPaintableId(String paintableId) {
        this.paintableId = paintableId;
        debug("paintableId=" + paintableId);
    }

    /**
     * Get the paintable id of the applet widget.
     *
     * @return The id of this applet widget in the Vaadin application.
     */
    protected String getPaintableId() {
        return paintableId;
    }

    /**
     * Set the application session cookie. Called from init.
     *
     * @param appUrl
     */
    private void setApplicationSessionCookie(String appSessionCookie) {
        sessionCookie = appSessionCookie;
        debug("sessionCookie=" + sessionCookie);
    }

    /**
     * Get the application session cookie.
     *
     * @return The session cookie needed to communicate back to the Vaadin
     *         application instance.
     */
    protected String getApplicationSessionCookie() {
        return sessionCookie;
    }

    /**
     * Set the application URL. Called from init.
     *
     * @param appUrl
     */
    private void setApplicationURL(String appUrl) {
        applicationURL = appUrl;
        debug("applicationURL=" + applicationURL);
    }

    /**
     * Get the application URL.
     *
     * @return The URL of the Vaadin application.
     */
    protected String getApplicationURL() {
        return applicationURL;
    }

    public String getAction() {
		return action;
	}

	public void setAction(String action) {
		System.out.println("AbstractVaadinApplet: "+action);
		this.action = action;
	}

	/**
     * Debug a string if debugging has been enabled.
     *
     * @param string
     */
    protected void debug(String string) {
        if (!isDebug()) {
            return;
        }
        System.err.println("debug: " + string);
    }

    /**
     * Stop the poller and destroy the applet.
     *
     */
    @Override
    public void destroy() {
        runPoller = false;
        super.destroy();
    }

    /**
     * Invokes vaadin.forceSync that synchronizes the client-side GWT
     * application with server.
     *
     */
    public void vaadinSync() {
        jsCallAsync("vaadin.forceSync()");
    }

    /**
     * Invokes vaadin.appletUpdateVariable sends a variable to server.
     *
     * @param variableName
     * @param newValue
     * @param immediate
     */
    public void vaadinUpdateVariable(String variableName, boolean newValue,
            boolean immediate) {
        jsCallAsync("vaadin.appletUpdateBooleanVariable('" + getPaintableId()
                + "','" + variableName + "'," + newValue + "," + immediate
                + ")");
    }

    /**
     * Invokes vaadin.appletUpdateVariable sends a variable to server.
     *
     * @param variableName
     * @param newValue
     * @param immediate
     */
    public void vaadinUpdateVariable(String variableName, int newValue,
            boolean immediate) {
        jsCallAsync("vaadin.appletUpdateIntVariable('" + getPaintableId()
                + "','" + variableName + "'," + newValue + "," + immediate
                + ")");
    }

    /**
     * Invokes vaadin.appletUpdateVariable sends a variable to server.
     *
     * @param variableName
     * @param newValue
     * @param immediate
     */
    public void vaadinUpdateVariable(String variableName, double newValue,
            boolean immediate) {
        jsCallAsync("vaadin.appletUpdateDoubleVariable('" + getPaintableId()
                + "','" + variableName + "'," + newValue + "," + immediate
                + ")");
    }

    /**
     * Invokes vaadin.appletUpdateVariable sends a variable to server.
     *
     * @param variableName
     * @param newValue
     * @param immediate
     */
    public void vaadinUpdateVariable(String variableName, String newValue,
            boolean immediate) {
        jsCallAsync("vaadin.appletUpdateStringVariable('" + getPaintableId()
                + "','" + variableName + "','" + newValue + "'," + immediate
                + ")");
    }

    /*
     * TODO: Variable support missing for: String[], Object[]
, long, float,
     * Map<String,Object>, Paintable
     */

    /**
     * Execute a JavaScript asynchronously.
     *
     * @param command
     */
    public void jsCallAsync(String command) {
        JSCallThread t = new JSCallThread(command);
        t.start();
    }

    /**
     * Execute a JavaScript synchronously.
     *
     * @param command
     * @throws InterruptedException
     */
    public Object jsCallSync(String command) throws InterruptedException {
        JSCallThread t = new JSCallThread(command);
        t.start();
        t.join(MAX_JS_WAIT_TIME);
        return t.getResult();
    }

    /**
     * Thread for polling incoming JavaScript commands. Threading is used to
     * change the call stack. If an applet function is invoked from JavaScript
     * it will always use JavaScript permissions regardless of applet signing.
     *
     * This thread allows commands to be sent to the applet and executed with
     * the applet's privileges.
     *
     * @author Sami Ekblad
     */
    public class JsPollerThread extends Thread {

        private static final long POLLER_DELAY = 100;
        private String jsCommand;
        private Object[] jsParams;

        @Override
        public void run() {
            debug("Poller thread started.");
            while (runPoller) {

                // Check if a command was received
                String cmd = null;
                Object[] params = null;
                synchronized (pollerLock) {
                    if (jsCommand != null) {
                        cmd = jsCommand;
                        params = jsParams;
                        jsCommand = null;
                        jsParams = null;
                        debug("Received JavaScript command '" + cmd + "'");
                    }
                }

                if (cmd != null) {
                    doExecute(cmd, params);
                }

                try {
                    Thread.sleep(POLLER_DELAY);
                } catch (InterruptedException e) {
                }
            }
            debug("Poller thread stopped.");
        }
    }

    /**
     * Thread for executing outgoing JavaScript commands. This thread
     * implementation is used to asynchronously invoke JavaScript commands from
     * applet.
     *
     * @author Sami Ekblad
     *
     */
    public class JSCallThread extends Thread {

        private String command = null;
        private Object result = null;
        private boolean success = false;

        /**
         * Constructor
         *
         * @param command
         *            Complete JavaScript command to be executed including
         */
        public JSCallThread(String command) {
            super();
            // SE: We need to remove all line changes to avoid exceptions
            this.command = command.replaceAll("\n", " ");
        }

        @Override
        public void run() {

            debug("Call JavaScript '" + command + "'");

            String jscmd = command;

            try {
                Method getWindowMethod = null;
                Method evalMethod = null;
                Object jsWin = null;
                Class<?> c = Class.forName("netscape.javascript.JSObject");
                Method ms[] = c.getMethods();
                for (int i = 0; i < ms.length; i++) {
                    if (ms[i]
.getName().compareTo("getWindow") == 0) {
                        getWindowMethod = ms[i]
;
                    } else if (ms[i]
.getName().compareTo("eval") == 0) {
                        evalMethod = ms[i]
;
                    }

                }

                // Get window of the applet
                jsWin = getWindowMethod.invoke(c,
                        new Object[] { AbstractVaadinApplet.this });

                // Invoke the command
                result = evalMethod.invoke(jsWin, new Object[] { jscmd });

                if (!(result instanceof String) && result != null) {
                    result = result.toString();
                }
                success = true;
                debug("JavaScript result: " + result);
            }

            catch (InvocationTargetException e) {
                success = true;
                result = e;
                debug(e);
            } catch (Exception e) {
                success = true;
                result = e;
                debug(e);
            }
        }

        /**
         * Get result of the execution.
         *
         * @return
         */
        public Object getResult() {
            return result;
        }

        /**
         * Get the result of execution as string.
         *
         * @return
         */
        public String getResultAsString() {
            if (result == null) {
                return null;
            }
            return (String) (result instanceof String ? result : result
                    .toString());
        }

        /**
         * Get the exception that occurred during JavaScript invocation.
         *
         * @return
         */
        public Exception getException() {
            return (Exception) (result instanceof Exception ? result : null);
        }

        /**
         * Check if the JavaScript invocation was an success.
         *
         * @return
         */
        public boolean isSuccess() {
            return success;
        }

    }

    public void setDebug(boolean debug) {
        boolean change = this.debug != debug;
        this.debug = debug;
        if (change) {
            debug("" + isDebug());
        }
    }

    public void debug(Exception e) {
        if (!isDebug()) {
            return;
        }
        System.err.println("debug: Exception " + e);
        e.printStackTrace();
    }

    public boolean isDebug() {
        return debug;
    }

    /**
     * Execute method that should be invoked from a JavaScript. This invokes a
     * second thread (with applet's permission) to execute the command.
     *
     * @param command
     * @param params
     */
    public void execute(String command) {
        execute(command, null);
    }

    /**
     * Execute method that should be invoked from a JavaScript. This invokes a
     * second thread (with applet's permission) to execute the command.
     *
     * @param command
     * @param params
     */
    public void execute(String command, Object[] params) {
        if (pollerThread == null) {
            debug("Poller thread stopped. Cannot execute: '" + command + "'");
            return;
        }
        synchronized (pollerLock) {
            pollerThread.jsCommand = command;
            pollerThread.jsParams = params;
        }
    }

    /**
     * Function to to actually execute a specific command.
     *
     * The inheriting applet must implement this to execute commands sent from
     * JavaScript.
     *
     * Implementation may be empty if no JavaScript initiated commands are
     * supported.
     *
     * @param command
     */
    protected abstract void doExecute(String command, Object[] params);

}

Screenshot addon:

-paintContent() line target.addUploadStreamVariable(this, “stream”) removed and line
target.addVariable(this, VAppletIntegration.ATTR_APPLET_ACTION,getStreamVariable()) added.

getStreamVariable() is method from Upload.class

With those changes I got in action parameter path for http post method, so in ScreenShot applet I replaced postUrl with action which is something like http://localhost:8080/app_name/APP/UPLOAD/PID*/action/*

Applet init() method:

added


action = getAction();

Applet doPostToServer() method:

PostMethod filePost = new PostMethod(postUrl); replaced with PostMethod filePost = new PostMethod(action);

Finally it works :slight_smile:

I hope this is helpful :smiley:

I think I found a couple of bugs in the Applet integration AddOn.


1)

If I update several variables and syncronize them afterwards, then sometimes not all variables are sent.

Example:
vaadinUpdateVariable(“var1”, “value”, false);
vaadinUpdateVariable(“var2”, “value”, false);
vaadinUpdateVariable(“var3”, “value”, false);
vaadinUpdateVariable(“var4”, “value”, false);
vaadinSync();

…sometimes it work. Sometimes one of them is missing when data is recieved serverside.


2)

If data contains backslashes then they tend to dissappear:

Example:
vaadinUpdateVariable(“path”, “\server\folder”, false);

…then on the serverside I get: “\serverfolder”

…but temporarily this fixes the bugs:


1)

try {
Thread.sleep(50);
} catch (InterruptedException ex) { }

    vaadinSync();


2)


@Override

public void vaadinUpdateVariable(String variableName, String newValue, boolean immediate) {
super.vaadinUpdateVariable(variableName,
escapeString(newValue)
, immediate);
}

private String escapeString(String text) {
    text = text.replace("\"", "\\\"");
    text = text.replace("\\", "\\\\");
    text = text.replace("\n", "\\n");
    return text;
}