package com.smartgwt.client.docs; /** * <h3>Smart GWT Architecture</h3> * 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. * <p> * 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. * <p> * 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. * <p> * 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. * <p> * Showing a dialog containing a "wizard" is a straightforward example of showing a "preloaded * view". For example: * <pre> * function showNewUserWizard() { * Window.create({ * items:[ * DynamicForm.create({ ... }) * ] * }); * } * Button.create({ * title:"New User..", * click:"showNewUserWizard()" * }); * </pre> * 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. * <p> * 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 {@link com.smartgwt.client.rpc.RPCManager} for information on RPCs and how to construct a .jsp that can * send an RPC response). * <pre> * 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()" * }); * </pre> * 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. * <P> * This architecture has several key advantages: * <dl> * * <dt><b>Performance: Cacheable UI</b></dt> * <dd> * A dynamic, data-driven UI can be expressed completely in <i>cacheable</i> 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. * <br> * 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 * {@link i18n internationalization} techniques such as using JSTL tags in a JSP remain * applicable. * <br> * 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. * <br> </dd> * * <dt><b>Performance: Minimal Server State</b></dt> * <dd> * 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. * <br> </dd> * * <dt><b>True Presentation / Business Logic separation</b></dt> * <dd> * 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. * <br> </dd> * * <dt><b>Parallel Development and Testability</b></dt> * <dd> * 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 <code>{ userName : "Bob" }</code>. * <br> * 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. * <br> * For more info on creating applications that support client-only testing, see * {@link com.smartgwt.client.docs.ClientOnlyDataSources Client Only DataSources}. * <br> </dd> * </dl> * <br> * <h3>Refinements</h3> * <br> * <b>Creating vs Showing a View</b> * <br> * 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 <i>creating</i> a view and <i>showing</i> an existing view. When * showing an existing view, the same components and/or data may be able to be reused. * <br> * 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 <code>showNewUserWizard()</code> 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. (<i>Note: "New User" button omitted for brevity * from here on</i>) * <pre> * 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(); * } * </pre> * * <b>Batching Operations</b> * <br> * 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 * {@link com.smartgwt.client.rpc.RPCManager#startQueue RPCManager.startQueue} to do so. * <pre> * function showNewUserWizard() { * if (!window.myWindow) { * Window.create({ * ID:"myWindow", * autoDraw:false, * items:[ * Canvas.create({ ID: "welcomeCanvas" }), * <b>ListGrid.create({ * ID: "myGrid", * dataSource:"myDataSource" * }),</b> * DynamicForm.create({ ... }) * ] * }); * <b>RPCManager.startQueue(); * myGrid.fetchData();</b> * RPCManager.sendRequest({ * actionURL:"getUserName.jsp", * callback:"doShow(rpcResponse)" * }); * <b>RPCManager.sendQueue();</b> * } else { * myWindow.show(); * } * } * function doShow(rpcResponse) { * welcomeCanvas.setContents("Hello, " + rpcResponse.userName); * myWindow.show(); * } * </pre> * * <b>Segmenting very large Applications</b> * <P> * 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. * <P> * 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. */ public interface SmartArchitecture { }