Package com.smartgwt.client.docs

# Interface SmartArchitecture

public interface SmartArchitecture

### Smart GWT Architecture

Smart GWT can add interactivity and performance benefits to any web application with a variety of integration approaches. This topic discusses the optimal architecture for a Smart GWT application, which can be adopted in whole or in part.

In a typical HTML-based web application, every time a new view is shown to a user, a round trip to the server is required to retrieve new presentation information, such as a search screen. However in an ISC-based application, showing a new view can be accomplished by simply hiding some components and showing others.

Because ISC components are expressed in a concise declarative form, and because ISC components have essentially no runtime performance impact until used, dozens of application views can be downloaded to the browser using the same bandwidth that would have been required to render just the initial view in plain HTML.

This architectural pattern of "preloading views" has tremendous benefits. View transitions which do not require new data from the server can be performed near-instantaneously and without server involvement, boosting both interactivity and scalability.

Showing a dialog containing a "wizard" is a straightforward example of showing a "preloaded view". For example:

         function showNewUserWizard() {
             Window.create({
                 items:[
                     DynamicForm.create({ ... })
                 ]
             });
         }
         Button.create({
             title:"New User..",
             click:"showNewUserWizard()"
         });

In this example, none of the components involved in a potentially multi-pane wizard are created until they are needed. Showing the wizard has near-instantaneous response and causes no server load.

However, let's say that the first pane of the wizard is going to incorporate some dynamic user-specific data, such as the current user's name. To load the username, we'll use an RPC operation targetting a .jsp called "getUserName.jsp" and show the wizard when it completes (see `RPCManager` for information on RPCs and how to construct a .jsp that can send an RPC response).

         function showNewUserWizard() {
             RPCManager.sendRequest({
                 actionURL:"getUserName.jsp",
                 callback:"doShow(rpcResponse)"
             });
         }
         function doShow(rpcResponse) {
             Window.create({
                 items:[
                     Canvas.create({contents:"Hello, " + rpcResponse.userName}),
                     DynamicForm.create({ ... })
                 ]
             });
         }
         Button.create({
             title:"New User..",
             click:"showNewUserWizard()"
         });

In this example, we've simply incorporated a user name into the first pane of a wizard. However, this pattern allows us to arbitrarily change user interactions based on data from the server. For example, the RPCResponse might have contained a flag indicating that the wizard should skip the first two steps, or an arbitrary warning message for the user, or even JavaScript code to be evaluated on the client.

This architecture has several key advantages:

Performance: Cacheable UI
  A dynamic, data-driven UI can be expressed completely in cacheable JavaScript. This is in contrast to any architecture based on server-side HTML generation, where static parts of the presentation are mixed in with dynamic data, preventing cacheability so that bandwidth and server time are wasted repeatedly delivering the same static presentation data.
  Even generated JavaScript is cacheable. For example, a Smart GWT View expressed in XML and contained within a JSP is still a separately cacheable resource when loaded via a <SCRIPT SRC> tag and advertised as a cacheable resource via HTTP headers, because it is ultimately delivered to the browser as simple JavaScript. Hence standard `internationalization` techniques such as using JSTL tags in a JSP remain applicable.
  The Smart GWT Architecture even allows you to capture all the gradations of cacheability from completely static (changes once per application rollout) to completely dynamic (timestamp). In the example above, the user name wouldn't actually change for the lifetime of the page, so could be loaded once only.
Performance: Minimal Server State
  Any architecture that relies on component descriptions being generated by the server must track a great deal of state, which, in the Smart GWT Architecture, is either completely eliminated or greatly reduced.
True Presentation / Business Logic separation
  The RPCResponse object represents the client's exact, minimal needs for server data. This is much easier to understand and to audit than a slew of .jsp files which access and update miscellaneous state. It is also far easier to spot reusable patterns of data access, which in server-side HTML generation systems often end up as duplicated code.
Parallel Development and Testability
  Using the Smart GWT architecture allows you to build a complete, working application that can run without a server, based on sample data. In the example above, it would be straightforward to create a testing mode that returned a faked RPC response consisting of simply `{ userName : "Bob" }`.
  This allows better parallel development by enabling the client side of the system to be tested in isolation, and creates clearer communication between client and server-side developers since creation of test data tends to develop into data requirements specifications.
  For more info on creating applications that support client-only testing, see `Client Only DataSources`.

### Refinements

Creating vs Showing a View
Many views will be shown to the user repeatedly, for example, the user may repeatedly switch back and forth between two panes of a TabSet. In that usage it makes sense to make a distinction between creating a view and showing an existing view. When showing an existing view, the same components and/or data may be able to be reused.
In the following variant on the original example, we only create the Window object and do the RPC to retrieve the user name the first time `showNewUserWizard()` is called. Subsequently we reuse the existing window, and we assume the user name has not changed, so we need not do the RPC again. (Note: "New User" button omitted for brevity from here on)

         function showNewUserWizard() {
             if (!window.myWindow) {
                 Window.create({
                     ID:"myWindow",
                     autoDraw:false,
                     items:[
                         Canvas.create({ ID: "welcomeCanvas" }),
                         DynamicForm.create({ ... })
                     ]
                 });
                 RPCManager.sendRequest({
                     actionURL:"getUserName.jsp",
                     callback:"doShow(rpcResponse)"
                 });
             } else {
                 myWindow.show();
             }
         }
         function doShow(rpcResponse) {
             welcomeCanvas.setContents("Hello, " + rpcResponse.userName);
             myWindow.show();
         }

Batching Operations
A view may incorporate multiple components, each of which requires data. In the following example, a DataBound ListGrid has been incorporated into the wizard, and we'd like to fetch the user's name and the beginning dataset for the grid in the same batch. We use `RPCManager.startQueue()` to do so.

         function showNewUserWizard() {
             if (!window.myWindow) {
                 Window.create({
                     ID:"myWindow",
                     autoDraw:false,
                     items:[
                         Canvas.create({ ID: "welcomeCanvas" }),
                         ListGrid.create({
                             ID: "myGrid",
                             dataSource:"myDataSource"
                         }),
                         DynamicForm.create({ ... })
                     ]
                 });
                 RPCManager.startQueue();
                 myGrid.fetchData();
                 RPCManager.sendRequest({
                     actionURL:"getUserName.jsp",
                     callback:"doShow(rpcResponse)"
                 });
                 RPCManager.sendQueue();
             } else {
                 myWindow.show();
             }
         }
         function doShow(rpcResponse) {
             welcomeCanvas.setContents("Hello, " + rpcResponse.userName);
             myWindow.show();
         }

Segmenting very large Applications

If an application has many hundreds of views, but only a handful of views are used by a given user in a typical session, for the fastest loading performance you should consider loading only the most commonly used views initially then loading further views on demand.

You can use FileLoader.loadJSFiles() to load a set of JavaScript files compromising an application module that defines a set of related views. The loaded JavaScript files may define new component classes and new DataSources in addition to defining new views and their associated logic.