Thinking About Design with WebObjects

Last modified by Pascal Robert on 2012/03/09 16:04

Thinking About Design with WebObjects

How a WebObjects Developer Thinks

Relationships not Queries

Qualifiers

Fetch Specifications

Business Logic for Business Objects

Components are for View Not Process

Object Design

The Request - Response Loop

Each action taken by a user is communicated to your application via the web server and the WebObjects adaptor. All the pertinent details of the user’s action--the contents of text fields, the state of radio buttons and checkboxes, and the selections in pop-up menus--as well as information about the session and the button or link activated is encoded in the HTTP request.
 The request is decoded by the action of the WebObjects adaptor and default application behavior. This decoding process, which culminates in the generation of a response page to be returned to the web browser, constitutes the request-response loop. Figure 2 shows the sequence of messages invoked when processing a request.

WebObjects has two request-processing models: component actions and direct actions.
 ■ The component actions model allows you to maintain state in applications; therefore, it requires and uses session objects. By default, web applications use this model.
 ■ The direct actions model is used by applications that don’t require state management---for example, search engines, product catalogs, document libraries, and dynamic publishing. Applications that use this model don’t have session objects by default.

When developing an application, you are not restricted to one request-processing model. Applications can use the model most appropriate to implement specific features. Component actions are generally useful in web applications with interconnected components; however, they do not give the user a great deal of control over an application’s flow. For example, a user cannot directly execute a method defined in the Java source file of a web component. Direct actions, on the other hand, are better suited at providing users such access. For example, using the appropriate URL, users can execute specific methods of an application.

The application object is an instance of Application where Application is a subclass of WOApplication. A session object is an instance of Session where Session is a subclass of WOSession. An instance of Application is created when your application launches, and an instance of Session is created for each initial user. Note that sessions may time out. You can configure the time out duration when deploying an application.

Awake
 public void awake()
 The application, session, and component objects are awakened. Custom initialization logic can be added in this phase.

Sync
 public void
 takeValuesFromRequest
 (WORequest, WOContext)
 Form data is read into the instance variables the WebObjects elements are bound to. Key-value coding set methods are invoked.

Action
 public WOActionResults
 invokeAction (WORequest,
 WOContext)
 The action the user triggered--with a link or a submit button--is performed. The action could create a new page.

Response
 public void
 appendToResponse
 (WOResponse, WOContext)
 The response page is generated. The form elements’ contents are set to the values stored in the instance variables the WebObjects elements are bound to. Key-value coding accessor methods are invoked.

Sleep
 public void sleep()
 The application, session, and component objects are put to sleep. Custom deactivation logic can be added in this phase.

Application

Session

Component

awake

 

 

 

awake

 

 

 

awake

takeValuesFromRequest

 

 

 

takeValuesFromRequest

 

 

 

takeValuesFromRequest

 

 

Set methods invoked.

invokeAction

 

 

 

invokeAction

 

 

 

invokeAction

appendToResponse

 

 

 

appendToResponse

 

 

 

appendToResponse

 

 

Accessor methods invoked. Response page generated.

 

 

sleep

 

sleep

 

sleep

 

 

Processing the Request

Request processing takes place in three stages: awake, sync, and action.

■ Awake. This stage is carried out when WebObjects sends awake messages to several objects.

In a multi-user system, limited resources need to be used as efficiently as possible. To this end, applications are active only while they perform a task. A single server can be running several applications or many instances of the same application. Application instances are active only while processing requests. See “Generating the Response” (page 16) for more information.
 The application object’s awake method is invoked first, then the session object’s awake method, and, for component action--based requests, the web component’s awake method. You can customize the method in each of the corresponding classes to add logic that needs to be performed before processing the request. Even though the default implementations of these awake methods do nothing, you should invoke the superclass implementation before executing custom logic, as here:


public void awake() {
        super.awake();
       /* Custom logic goes here. */
   }

Sync. During this stage, the takeValuesFromRequest method is invoked, which causes the values entered in form elements by the user to be copied into the corresponding instance variables. This stage is skipped if the component contains no form elements or if the values of the form elements are not changed.
 WebObjects invokes the application object’s takeValuesFromRequest method. The application then invokes the session object’s corresponding method, which in turn invokes the web component’s method (for component action-based requests). The component invokes each dynamic element’s takeValuesFromRequest method, which causes form elements to copy the values from the request into the appropriate component bindings. WebObjects uses key-value coding-implemented by the NSKeyValueCoding interface in (com.webobjects.foundation--to determine how to set the value of the binding.

To set the value of a key named key, key-value coding looks for an available set method or an instance variable in the following order:
 1. public void setKey()
 2. private_setKey()
 3. _key
 4. key

Action. During this stage, the action the user chose is executed by invoking the invokeAction method.
 Like the takeValuesFromRequest method, WebObjects invokes the application’s invokeAction method. The application then invokes the session’s method, which in turn invokes the web component’s method (for component action--based requests). The component then sends invokeAction to each of its dynamic elements.
 When the invokeAction method of the dynamic element that triggered the request is invoked--for example, a submit button--the dynamic element sends the message bound to its action attribute.

Generating the response

After the form values are gathered and the action method is invoked, the application creates a response page. This is the web component returned by the action method. The response-generation process has two phases: response and sleep.

■ Response. The response page is generated during this phase. Each dynamic element’s appendToResponse method is invoked, so that it can add its content to the rendered webpage.

WebObjects invokes the application’s appendToResponse method. Then the application invokes the session’s method, which in turn invokes the web component’s method. The component goes through its HTML code creating the page’s content. When it finds a WEBOBJECT element, it invokes its appendToResponse method, so that it can get the values of its bindings and add the resulting content to the page. The process continues recursively until the entire response page is generated.

Again, WebObjects uses key-value coding when a variable needs to be accessed or set. When the value of a key named key is requested, key-value coding first looks for an accessor method. If one is not found, it accesses the instance variable itself. The order in which key-value coding tries to obtain the value for key is as follows:
 1. public [] getKey()
 2. public[]key()
 3. private[]_getKey()
 4. private[]key()
 5. []_key
 6. []key

■ Sleep. When the response process is completed, the sleep methods of the web component, session, and application objects are invoked. (The order in which the objects’ sleep method is called is the opposite of the order in which the awake methods are invoked in the awake phase.) When overriding the sleep method, you should incorporate the superclass implementation at the end of the method as shown in Listing 2. After all the objects involved in the request-response process are put to sleep, the new page is sent to the WebObjects adaptor.


Listing 2 Overriding the sleep method public void sleep() {
                /* Custom logic goes here. */
                 super.sleep();
            }

Why Defer Optimization Concerns

Key Value Coding and WOGNL Extensions

In order for models, views, and controllers to be independent of each other, you need to be able to access properties in a way that is independent of a model’s implementation. This is accomplished by using key-value coding.

Keys

You specify properties of a model using a simple key, often a string. The corresponding view or controller uses the key to look up the corresponding attribute value. The “value for an attribute” construction enforces the notion that the attribute itself doesn’t necessarily contain the data—the value can be indirectly obtained or derived.
 Key-value coding is used to perform this lookup—it is a mechanism for accessing an object’s properties indirectly and, in certain contexts, automatically. Key-value coding works by using the names of the object’s properties—typically its instance variables or accessor methods—as keys to access the values of those properties.

For example, you might obtain the name of a Department object using a name key. If the Department object either has an instance variable or method called name, then a value for the key can be returned. Similarly, you might obtain Employee attributes using the firstName, lastName, and salary keys.

Values

All values for a particular attribute of a given entity are of the same data type. The data type of an attribute is specified in the declaration of its corresponding instance variable, the return value of its accessor method, or simply in the object model. For example, the data type of the Department object name attribute may be an String object in Java. Note that key-value coding returns only object values.

The value of a to-one relationship is simply the destination object of that relationship. For example, the value of the department property of an Employee object is a Department object.

The value of a to-many relationship is a collection object (an array) that contains the destination objects of that relationship. For example, the value of the employees property of Department object is a collection containing Employee objects.

Key Paths

A key path is a string of dot-separated keys that specify a sequence of object properties to traverse. The property of the first key is determined by, and each subsequent key is evaluated relative to, the previous property. Key paths allow you to specify the properties of related objects in a way that is independent of the model implementation. Using key paths you can specify the path through an object graph, of arbitrary depth, to a specific attribute of a related object.

The key-value coding mechanism implements the lookup of a value given a key path similar to key-value pairs. For example, you might access the name of a department via an Employee object using the department.name key path where department is a relationship of Employee and name is an attribute of Department.

Not every relationship in a key path necessarily has a value. For example, the manager relationship can be null if the employee is the CEO. In this case, the key-value coding mechanism does not break—it simply stops traversing the path and returns an appropriate value, such as null.

Description of the Application to be Built (blog)