Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page > Hide TOC

The Rule System

Direct to Web stores its configuration in the form of rules. The following is an example of a rule:

((task= "query") and (not (attribute = null))
    and (attribute.valueClassName= "java.lang.String")
    => componentName = "D2WQueryStringComponent"

A rule consists of five parts, of which three are shown in the example:

Deciding Which Candidate Should Fire

When the Direct to Web context asks for the value for a key, there are typically several rules that can fire. For example, consider the following rules to resolve the componentName key:

*true*=> componentName = "D2WUneditable"
 
(task = "inspect") =>componentName = "D2WDisplayString"
 
((task = "inspect") and
    (attribute.valueClassName= "com.webobjects.foundation.NSTimestamp"))
    => componentName = "D2WDisplayDate"

The left-hand side of the first rule is always true. Such rules are useful for providing “fallback” values when all other rules fail to fire. Note that if the left-hand side for the third rule is true, all three rules are candidates for firing. The rule engine must choose which rule will fire.

To make the choice, Direct to Web employs a priority system. Each rule has a priority. The single rule with the highest priority fires. By convention, the following priorities are used in Direct to Web.

Priority

Description

0-10

Reserved for Direct to Web framework and fallback rules

100-105

WebAssistant rules

If two or more rules have the same priority, the rule with the most specific left-hand side (applying to the least number of cases) fires. Direct to Web measures how specific a rule is by counting the number of clauses joined by an and operator; the more clauses the rule has, the more specific it is. Clauses joined by the or operator count as a single clause.

If two or more rules have the same priority and are equally specific, Direct to Web arbitrarily chooses one.

The rule system resolves keys recursively. In other words, the rule system can resolve a rule based on the outcome of another rule. Consider a rule for the pageName key:

((look= "BasicLook") and (task = "query")) => pageName = "BASQueryPage"

The look key is defined by a rule like this:

*true*=> look = "BasicLook"

To resolve the pageName key, the rule engine asks the Direct to Web context for values for the look and the task keys. The Direct to Web context then invokes the rule engine to resolve the look key. This extra step isn’t necessary for the task key; it’s already in the Direct to Web context’s local dictionary. Although recursive rules are powerful, they can hamper Direct to Web’s performance.

To see the rules that fire as Direct to Web renders pages, run your application with the switch -D2WTraceRuleFiringEnabled YES.

Rules and the Web Assistant

The Web Assistant defines rules that pertain to specific entities and properties in your application, unlike the rules from the Direct to Web framework. These rules have a priority of 100, which override the default rules in the Direct to Web framework. Consequently, if you want to define your own default rules that the Web Assistant can override, you need to specify them with a priority between 11 and 99.

When you click Update in the Web Assistant window, the settings are compared to the settings on the server and the appropriate rules are added or deleted from the rule database in memory. When you click Save in the Web Assistant window, the rule database is stored in the application’s user.d2wmodel file.

To build the Web Assistant’s list of available task pages and property-level components, Direct to Web uses the rule system differently from when it renders a page. Instead of firing the single best candidate rule to find a particular key, Direct to Web asks for all rules that can resolve the key given the state of the Direct to Web context and collects the resulting values into a list that the Web Assistant presents to you. Two special keys are handled this way: pageAvailable for collecting task pages and componentAvailable for collecting property-level components.

If you want to see which rules the Web Assistant creates and deletes at runtime, you can run your application with the switch -D2WTraceRuleModificationsEnabled YES.

Rule Firing Cache

When a rule fires, its right-hand-side value is cached to improve Direct to Web’s rendering performance. Once the value is cached, subsequent requests for the key may cause the rule engine to access the cache to resolve its value instead of finding a rule to fire. The cache is retained for the life of the application or until you click Update, Save, or Revert in the Web Assistant.

It is important to note that the right-hand-side value is cached based on the values of a collection of keys that does not necessarily include all of the keys on the left-hand side of the rule. Only the values of a list of significant keys and the right-hand-side key are used to uniquely identify the cache entry. By default, the significant keys are

The configuration key refers to the named configuration of the current page. You can add to this list using the D2W class’s newSignificantKey method.

Consider this rule:

((task= "edit") and (entity.name = "Customer")
    and (propertyKey = "agent"))
    => componentName = "D2WEditToOneRelationship"

When it fires, Direct to Web creates the cache entry described in Table 2-8.

Table 2-8  Example of Cached Rule

task

“edit”

entity

<EOEntity Customer>

propertyKey

“agent”

configuration

null

key

componentName

value

“D2WEditToOneRelationship”

If the Direct to Web context is asked for the value of the componentName key again, and the context’s values for task, entity, propertyKey, and configuration are unchanged, this rule does not fire. Instead, the rule system uses the cached value. On the other hand, if the value of any of these keys changes, the cache entry no longer applies and the rule engine must find a rule to fire to resolve the componentName key.

Caching Gotchas

If you watch the rules as they fire (with -D2WTraceRuleFiringEnabled YES), you may find rules that fire when you expect Direct to Web to use the values in the cache. Or rules you expect to fire don’t appear because Direct to Web gets the values from the cache.

To see how a rule might fire when you expect its value to be cached, consider the rule that resolves the look key, which defines whether the application is using the Basic look, the Neutral look, or the WebObjects look. Suppose the rule is

*true*=> look = "NeutralLook"

The first time this rule fires is when the Direct to Web factory asks for the name of the Direct to Web template to display the QueryAll page. The following cache entry is created:

Table 2-9  Example of Cached Rule First Time it Fires

task

“queryAll”

entity

null

propertyKey

null

configuration

null

key

look

value

“NeutralLook”

Note that the entity key is null. The next time Direct to Web asks for the look key is when it wants to know the background color for the Query form table. The entity is still null so Direct to Web gets the value from the cache.

Now the QueryAll template begins to iterate through the entities. It sets the first entity to the Administrator EOEntity. This time the entity key is no longer null so the old cache entry does not apply. Consequently, the rule engine fires the look rule again.

What is more difficult to debug is when the rule engine resolves a key using the cache when you expect a rule to fire. This happens when the outcome of the rule depends on a key that is not cached (that is, not in the list of significant keys). This can arise in an application that has different behavior depending on the user’s access privileges.

Consider an online real estate database application that behaves differently based on the user’s access privileges. In particular, the real estate agent (access level 1) sees the AgentListListing template and the customer (access level 3) sees the CustomerListListing template. You can set this up with these rules:

((task= "list") and (entity = "Listing") and (session.user.accessLevel= 1))
    => pageName = "AgentListListing"
 
((task = "list") and (entity= "Listing") and (session.user.accessLevel = 3))
    => pageName = "CustomerListListing"

Suppose the real estate agent logs into the application and accesses the list page. Direct to Web creates this cache entry:

Table 2-10  Cached Rule for Real Estate Agent Login

task

“list”

entity

<EOEntity Listing>

propertyKey

null

configuration

null

key

pageName

value

“AgentListListing”

task

entity

propertyKey

configuration

key

value

“list”

<EOEntityListing>

null

null

pageName

“AgentListListing”

Later a customer logs on and accesses the list page. Instead of showing the customer list page, Direct to Web displays the real estate agent’s list page, which is an obvious security violation. This happens because the second rule never fires. Instead, the cache entry from the first rule resolves the value for the pageName key.

To fix the application, you need to add session.user.accessLevel to the list of significant keys using the D2W class’s newSignificantKey method. For example, D2W.factory().newSignificantKey("session.user.accessLevel");.



< Previous PageNext Page > Hide TOC


Last updated: 2007-07-11




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2007 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice