Multithreading and asynchronous updates/repaints with WebCream

This section addresses deploying applications that use multiple threads of execution to perform business logic and user interface updates. When such an application is deployed using WebCream, problems may surface where WebCream will capture an intermediate state of a window and generate a page, and the final state of the window will not be shown. A typical example where this problem can occur is if in response to a button click the application displays a “Please wait…” dialog, starts a new thread to do the actual work and returns. When the newly started thread completes, it hides the Wait dialog and updates the window. If this application is deployed using WebCream there is a chance that when the web users press a button on the HTML page what they will get in return will be a page with the Wait dialog, not the window that is updated or shown eventually.

The reason why this undesired behavior may happen is because WebCream considers the action to be complete when the application returns from the event handling routine, for example actionPerformed listener for a button or itemListener for a checkbox. WebCream doesn’t know if the newly spawned threads represent a background process that is unrelated to the user interface, or if they actually perform the business logic and the action is not complete until they are finished. Note that using SwingUtilities.invokeLater and SwingUtilities.invokeNow should not be a problem, although it is not guaranteed.

While it may look like a serious problem, the solution is most of the times very easy and can be implemented quickly. There are three alternatives that can provide a solution to multithreading issues.

Manipulating WebCream application properties to accommodate multithreading

The easiest way to solve asynchronous response related problems is achieved by adding properties to WebCream application properties file. The application properties file is created either by WebCream Console or manually and by default is located in the tomcat/webapps/webcream/conf directory. WebCream allows you to refer to windows and components by their "logical" names. For details of naming read Referring to windows and components in WebCream. A logical name of a window/button is comprised by taking the window title/button text, trimming any leading and trailing spaces, and then replacing any spaces with '_' (underscore). To refer to a window in the application properties file one should use window.<window-title>, and to refer to a component one should use window.<window-title>.<component-type>.<component-title>. For example, if you have a login dialog with the title "Login to server" with a button "OK" then the references in the properties file would be

window.Login_to_server
window.Login_to_server.button.OK

Now that we know how to refer to components, let's see how we can put that to use. Suppose that your window gets updated dynamically after it has been displayed. Most common examples include a progress bar or some sort of a status window that is updated by a background running thread. WebCream will render an HTML page that will capture the current state of the window, but the subsequent updates will not be reflected. The easiest way to solve this problem is to add either autoRefresh or autoSubmit properties to your configuration file. You can specify the number of seconds after which the page should be automatically refreshed or updated so the user will be informed of the progress. The difference between the two is that autoRefresh ignores any text entered by the user while autoSubmit sends the currently entered data to the server before updating the page.

In another scenario, suppose that when OK button is pressed the actionPerformed listener spawns a new thread and returns immediately. When the new thread finishes the login operation, it hides the Login dialog and displays the main frame titled "Main Frame". What we will want to do is tell WebCream that even though the listener returns, the operation is still active and we only want it to finish when a window with title "Main Frame" became visible. Note that the title matching is done with Java startsWith function, which means that even if the title is "Main Frame of my application" it will still match. This can be accomplished by adding the following line to the property file

window.Login_to_server.button.OK.action=Main_Frame

Other possible values to action key are wc_next_window and wc_new_window. wc_next_window means that the operation ends when any other window, newly created or previously shown, becomes visible on top of the currently focused window. wc_new_window means that the operation ends when a new window is created. Examples of these predefined values are shown below

window.Login_to_server.button.OK.action=wc_next_window
window.Login_to_server.button.OK.action=wc_new_window

So far action key for buttons is the only supported configurable operation. For more flexibility see the next solution.


Programmatically controlling operations using WebCreamManager class

If the using application properties to synchronize WebCream operations with the business logic does not provide sufficient control, one can opt for programmatic integration with WebCream via WebCreamManager class. WebCreamManager defines a facade into the complex world of CreamTec virtual runtime environment by exposing a number of static methods. The beauty of the design is that refering to WebCreamManager does not make your code dependent on presense of WebCream because it will work with or without WebCream. WebCreamManager has a function boolean isWebCreamRunning() which allows the application to query if it is running under WebCream. To make matters even simpler, WebCreamManager gives two methods that allow the application programmer to directly demarcate the logic operation beginning and its end. The methods are

public static void beginOperation ()
public static void endOperation ()

As a developer or integrator, all you would have to do is call beginOperation() before you return from the event handling logic and call endOperation() at the end of the asynchronous processing, even if it is called from a different thread. For example, suppose you have a login dialog with OK button that sets the hourglass cursor, spawns a worker thread and returns; when the worker thread has received a response from the server, it removes the hour glass cursor and hides the dialog. In this case your event handling code would look as follows

import creamtec.webcream.WebCreamManager;

void btnOK_actionPerformed(ActionEvent e) {
    // tell WebCream that the logic operation will span multiple threads
    WebCreamManager.beginOperation();

    setHourglassCursor();
    // spawn worker thread
    new LoginWorkerThread(this).start();
}

... and the worker thread's run method will look like this

public void run() {
    // do business logic to login into the server
    doLogin();

    // Tell WebCream that the logic operation that was started in the event handler is finished
    WebCreamManager.endOperation();
}

When run in WebCream virtual runtime environment, the above code will cause WebCream to wait even after btnOK_ActionPerformed method has returned until endOperation is called in run method of the worker thread. When run as a stand alone application without WebCream, beginOperation and endOperation methods will do nothing. Notice that WebCreamManager class is distributed separately so that you can package it with your application when you distribute it without WebCream. See JavaDoc on WebCreamManager for programming details.

Summary

Differences between GUI and HTML models may prevent certain Java applications using multithreading from being rendered correctly. WebCream exposes a simple API that can be used to control when the rendering occurs. Integration with this API is easy and does not prevent the applications and applets from being run in a stand- alone mode as before.