. | ||||||||||||||||||||||||||||||||||||||||||
3. Pages and Forms Architecture3.1 ServletFormThe Mapper presentation framework for the web is modeled after a the architechure of a typical GUI/Swing type application. A single servlet dispatches requests to the appropriate ServletForm. The ServletForm is a container similar to a Swing JFrame. You create the various forms for your application by extending this base class. The ServletForm dispatches commands and data from the request object to the individual components it contains. The dispatching occurs in the doGet method of the ServletForm. The ServletForm is a reusable object. The ServletApp (master servlet) will normally recycle ServletForms unless their recycle method returns false. The recycle method in the ServletForm dispatches a RecycleEvent to all components. The ServletForm is composed of many subcomponents to support the processing of the request: ServletParameterDispatcher, ServletInputDispatcher, RenderDispatcher, ServletTriggerDispatcher, RecycleDispatcher, DocumentAdapter and Responder. The following is an example of a very simple ServletForm which contains a single component to display the current time: public class FirstPage extends ServletForm { TextField currentTime = new TextField(DataTypes.TYPE_DATE); public FirstPage() { this.setDocumentURI("resource:///forms/FirstPage.html"); currentTime.setId("currentTime"); this.add(currentTime); } protected void initForm() throws java.lang.Exception { super.initForm(); } protected void openForm() throws java.lang.Exception { currentTime.setValue(new Date()); } The following is the HTML which is used for by this ServletForm: <html> <head> <title>MapperXML Example: The FirstPage</title> </head> <body> <h1>MapperXML Example: The FirstPage</h1> <p>The current time is: <span id="currentTime">00:00:00</span></p> </body> </html> 3.2 Request Processing Cycle - doGetThe ServletApp invokes the ServletForm's doGet method to process the request. This method is invoked by the ServletApp for all request types (GET, POST, etc). The doGet method breaks the single request up into a sequence of events:
3.3 DispatchersThe ServletForm uses a set of specialized subcomponents called dispatchers. These subcomponents dispatch messages to the components you define in the ServletForm. As you add components (TextFields, Triggers, Parameters) to the ServletForm (Container), those components register with one or more dispatchers to receive notification about events they are interested in. It is critical to make sure you ADD components you create to the ServletForm (or a nested container). If you omit this, your components will not be notified of any events. Container hierarchy is supported, so as long as a component is added to some container (who is ultimately a child of the ServletForm), it will receive notification. There are separate dispatchers for each type of event. Some of these include:
3.4 Document AdapterThe actual XML/HTML document is rendered through the use of a XML/HTML template. The XML/HTML template does NOT contain any code. The Components are bound to the template through the use of the ID attribute: <p id=greeting>Hello greeting-name</p> A TextField would have its ID property set to "greeting". When instructed by its container (ServletForm), it would render its value to the XML/HTML template. The XML/HTML template is loaded, parsed into a Document Object Model (DOM) and cached by the ServletForm. The template is normally reused by the ServletForm. The DocumentAdapter can be created automatically by the container if you set the documentURI property. For automated creation, the container uses a DocumentAdapterBuilderFactory. This factory is configured to try using: JTidy, Xerces, JAXP or a user supplied DocumentAdapterBuilder to parse the DOM and create the DocumentAdapter. You can also manually code the creation of the DocumentAdapter. The Document is normally created and attached to this ServletForm in the initForm method. This method is normally only called once when the ServletForm is first invoked. Below is an example using the Xerces parser: public MyPage() { this.setDocumentURI("resource:///forms/MyPage.html"); } protected void initForm() throws Exception { super.initForm(); } 3.5 Multi-Part Request WrapperThe ServletForm also supports multipart type requests. A multipart request is sent by the browser when form data contains 1 or more uploaded files. To support this feature, if the incoming request has a content type of "multipart/form-data", the request is wrapped in another request object which is capable of processing multipart requests. The wrapper request is created via the createRequestWrapper method. By default, createRequestWrapper returns a HttpMultiPartServletRequest object which has a maximum file size of 1 megabyte and maximum single line size of 4,096 bytes. You can change this by overriding the createRequestWrapper method: protected HttpServletRequest createRequestWrapper(HttpServletRequest rq) throws Exception { HttpMultiPartServletRequest multi = new HttpMultiPartServletRequest(rq); // set maximum sizes if defaults if needed multi.setMaxFileSize(2048); multi.setMaxLineLength(80); // parse the request multi.parseRequest(); return multi; } 3.6 RespondersYou can control the response of this ServletForm by changing the Responder subcomponent at runtime. The default Responder is an HTMLResponder which sends the DOM Document as the response. There are a number of other types of responders you can use:
If your ServletForm needs to send more than one type of response, then you should create the appropriate set of responders and invoke the setResponder method of the ServletForm to change the responder. Below is a typical example of using responders. In this example, the ServletForm can respond by either sending the page, or redirecting the client to another page: ... HTMLResponder htmlResponder = new HTMLResponder(); ClientRedirectResponder clientRedirectResponder = new ClientRedirectResponder(); ... private void jbInit() throws Exception { ... clientRedirectResponder.setRedirectURL("/mapperex/index.html"); ... } ... protected void openForm() throws java.lang.Exception { // Set default responder setResponder(htmlResponder); ... } ... void saveButton_actionPerformed(TriggerEvent e) throws Exception { // Save changes and go to main menu delegate.saveChanges((PersonVO)holder.getValue); setResponder(clientRedirectResponder); } ... You can create your own responders by extending one of the existing responders or implementing the Responder interface. 3.7 ComponentsIn typical applications, you will add Components to this ServletForm and set their properties to bind to the DOM Document elements, the http request parameters, and value objects. These components are capable of modifying the DOM Document, storing and retrieving value from bound objects, and reading parameters from the http request, and parsing/converting between text values and java data types. This ServletForm is the base container for these components and contains dispatchers which dispatch events to the components. This ServletForm generates the events within the doGet method in a fixed sequence (see javadoc for doGet). The below example creates a HTMLInputText component which binds to an HTML form input text field. It also binds to the lastName property of a Java value object class. public class MyPage extends ServletForm { HTMLInputText lastName = new HTMLInputText(); VOValueHolder person = new VOValueHolder(); public MyPage() { lastName.setPropertyName("lastName"); lastName.setValueHolder(person); lastName.setId("lastName"); this.add(lastName); } ... protected void openForm() throws Exception { // Retrieve or create the value object Person personVO = new Person(1629, "Pulaski", "Katherine", null); // Bind value object to person ValueHolder person.setValueObject(personVO); } There are many components you can use in a ServletForm. Some of these include: Parameter, Template, TextField, Trigger, Button, HTMLAnchorURL, HTMLCheckBox, HTMLInputText, HTMLSelect, HTMLTextArea, and others. The next 2 chapters will describe the components in detail. 3.8 Component FactoriesMapperXML provides a feature to automate the creation of components at runtime. This feature can create the proper type of component, set many of its properties including:
This feature is provided by the HTMLComponentFactory.createComponents method. The createComponents method scans the HTML document looking for elements with an id attribute that match a specific syntax. It then creates the component, adds it to the container (in the proper heirarchy), binds it to the specified ValueHolder, sets the specified properties. This feature allows you to mix manually coded components with automatically created components. As it scans the HTML document to create components, it first checks the container for existing components. If a component already exists, it does not duplicate or modify the existing component. It does, however, move it to the correct position in the component heirarchy. The Only components which are bound to one of the given ValueHolders are created. The id's must also follow a strict syntax to be automatically created. 3.8.1 General Syntax for ID AttributeThe id must begin with a ValueHolder's alias. It must then be followed by a double-underscore ("__"). Next the propertyName must appear or the keyword "TEMPLATE_NODE". An optional suffix can be added to ensure unique id's (as required by spec). The optional suffix must be separated from the property name by a double-underscore("__"). The following are examples of valid id format:
The alias of the id (first part), must match an alias of a ValueHolder in the given array of ValueHolders, otherwise no Component will be created. The ValueHolder with a matching alias will be set as the new Component's valueHolder. If the new Component is an AbstractField subclass, then its propertyName will be set to the propertyName of the id (second part). If the given Element has a "name" attribute, the Component's parameter will be set to the value of the "name" attribute. If the new Component is a Template (or subclass), then only its collectionValueHolder property will be set. The associated ValueHolder for this Component must be a CollectionValueHolder, otherwise no Component will be created. 3.8.2 Format Control Syntax for ID AttributeThis method will also attempt to setup the formatting properties for the new Component. This only applies to AbstractField subclasses. The format is extracted from the document within the element's "value" attribute, "href" attribute, or text node. The format must be specified as TYPE:pattern, where TYPE is one of: DATE NUMBER or MSG. The pattern should be a valid pattern for the format type. The following are examples of use:
3.8.3 ID Attribute Syntax Examples
3.8.4 Example Code for HTMLComponentFactoryThe following is an example of a ServletForm which uses an HTMLComponentFactory to automatically create and bind all of the components (this example can be found in the distribution examples) public class ComponentFactoryPage extends ServletForm { private VOCollectionValueHolder invoice = new VOCollectionValueHolder(); private VOCollectionValueHolder invoiceItem = new VOCollectionValueHolder(); private BusinessDelegate bd; public ComponentFactoryPage() { try { jbInit(); } catch(Exception e) { e.printStackTrace(); } } private void jbInit() throws Exception { this.setDocumentURI("resource:///forms/ComponentFactoryPage.html"); invoice.setAlias("Invoice"); invoice.setValueObjectClass( com.taursys.examples.simpleweb.InvoiceVO.class); invoiceItem.setValueObjectClass( com.taursys.examples.simpleweb.InvoiceItemVO.class); invoiceItem.setAlias("InvoiceItem"); invoiceItem.setParentValueHolder(invoice); invoiceItem.setParentPropertyName("items"); } protected void initForm() throws java.lang.Exception { super.initForm(); // Fetch reference to the Business delegate bd = BusinessDelegate.getInstance(); // ========= Use HTMLComponentFactory to create components =========== HTMLComponentFactory.getInstance().createComponents(this, new ValueHolder[] {invoice, invoiceItem}); // =================================================================== } protected void openForm() throws java.lang.Exception { invoice.setCollection(bd.getAllInvoices()); } } 3.8.5 Component InventoryThe following is the table of components that the HTMLComponentFactory uses. You can override this table if you want.
3.8.6 Customizing Component FactoriesMapperXML provides an Abstract Class called ComponentFactory which is intended to automate the creation of Compents. You can create your own extensions of this class for specialized XML documents. MapperXML also provides a concrete subclass called HTMLComponentFactory. This class contains two primary methods:
The HTMLComponentFactory initializes the factory's tagTable with suggested components for HTML documents. During the automated Component creation, only the first suggestion is used. The other suggestions are intended for use by design tools. The following are the suggestions created by this class: |
||||||||||||||||||||||||||||||||||||||||||
. |