ABC Design Series: The ViewManager Part 1

by David Bayliss

Published 1999-11-23    Printer-friendly version

Part 1 of 2

Having dealt with the FileManager and RelationManager classes the final part of the file system I need to deal with is the ViewManager. It could be argued that having three different objects dealing with files is a little excessive. In a sense this is true; logically the ViewManager brings fairly little to the table over a RelationManager (it "just" deals with a bunch of files). However, the ViewManager does handle the very important special case where a bunch of files are being used to retrieve a series of records (including child lookups) in a nominated sequence. This was so vital I felt it deserved a special object. It turns out that the ViewManager is almost never used as a ViewManager, but it is the base class used for many of the higher level data access objects.

Room With A View

The ViewManager is to a View structure what a FileManager is to a File structure. Specifically, the ViewManager is there to act as an OOP front end to the view. It is also there to provide some logical sophistication not present in the native view. The main logical elements brought to the table are:

  1. Range Limits: The ABC and legacy template chains have the notion of a range limit, which is the ability to restrict the records retrieved to those matching one or more of the major-most elements of the key order. Tied in with the notion of range limits is the notion of a free element (the major-most element of a sort order that is not range limited).
  2. Multiple Sort Orders: A Clarion view structure only supports a single sort order (although the current sort order can be changed at will). The ViewManager is to support multiple sort orders (simply).
  3. Flexible filters: The Clarion view structure has one assignable filter. The ViewManager provides for multiple filters active at once.
  4. Attitude: A key requirement of ABC was that we wanted optimal (or near optimal) browse performance. It was felt that an essential element of that was ensuring that views were handled cleverly. Rather than us having to build the cleverness into every object that used the view (browse, drop down list, drop down combo, report, process etc) the ViewManager watches the commands being sent to the view structure and translates these commands (where required) into a more intelligent sequence.

Initialisation

The initialisation section of the ViewManager is quite large, and it also offends the OOP purists as it contains state; the order in which the methods are called is significant. These two are tied together. A significant procedure (say five browses and 15 drop combos) will contain 20 view initialisation sequences and possibly 100 sort order creation sequences. We felt that having these sequences concise, readable and efficient was more important than sheer hygiene.

The call sequence is:

Init
[ Repeat 1 or more times
    AddSortOrder
    AppendOrder ! Optional
    AddRange    ! Optional  
]
UseView
      AddRange PROCEDURE(*? Field)
      AddRange PROCEDURE(*? Field,*? Limit)
      AddRange PROCEDURE(*? Field,*? Low,*? High)
     

The three AddRange methods set a range limit upon the current sort order (defined by the preceding AddSortOrder or SetOrder). They correspond to Current Value, Single Value and High/Low Value range limits respectively. The code for each is similar. The aim of the code is to produce a RangeLimit queue with a queue record defined for each element of the key that is range limited.

The first line of code sets the type of the range limit. The second calls LimitMajorComponents. It is defined in ABC that if the range-limited field of a sort order is not the most major component then all the more major components are implicitly current-value limited irrespective of the limit-type of the more minor component. The call to LimitMajorComponents implements this detail.

The field(s) passed in is then added to the range-limit queue. Finally SetFreeElement is called to compute the free element of the sort order.

AddRange PROCEDURE(*? Field,RelationManager
       MyFile,RelationManager RelatedFile)

The purpose of this AddRange is the same as the other three, but the code is somewhat different because the information required to construct the range limit is not publicly available (it is hidden in the RelationManager). Essentially if two files are related by keys with, say, three components, then a FileLimit range limit corresponds to a single-value limit upon three different elements! The queue is thus filled in using the ListLinkingFields capability of the RelationManager.

AddSortOrder PROCEDURE(<KEY K>),BYTE,PROC

The AddSortOrder method actually performs the action of creating a new logical sort order. Each logical sort order can have a different range limit (and thus free element), and a different filter. This is stored in a queue (or Order queue) with a record pertaining to each sort order.

This method clears the queue record (it has to as it contains an ANY), stores the key, creates a new range-limit list and uses the first component of the key as the free element.

The sort order itself is computed by passing the key (if present) as a comma delimited list of components to the SetOrder method.

As it is impossible to remove sort orders it is okay to return the record number of the queue record added as the "unique identifier" of the sort order within the queue (for later use by SetOrder).

AppendOrder PROCEDURE(STRING Order)

Each time I look at the AddSortOrder/AppendOrder relationship I oscillate between deciding it is a beautifully elegant engineering solution and fretting that it is a complete hack. The issue is this: Proper database theory will tell you that sort orders should be defined in terms of fields and ascending/descending flags so that the logic of the program is nice and clean, and the ugliness of physical database design and actually getting performance out of the system can be left to some other poor schmuck.

The problem is that with many programmers coding furiously and requiring many different sort orders, the "poor schmuck" (typically the DBA) actually may not be able to get the system to perform at all! Worse yet he may be sufficiently senior that you can't boss him around to make sure your program runs ok.

Thus the programmers have to get pragmatic and they start building keys into their program logic. Performance improves greatly; unfortunately applications have to use a restricted set of sort sequences or the number of keys explodes.

So along comes ABC. What do we do, "restrictive" or "slow"? Legacy took the restrictive approach, which I didn't want, but the alternative wasn't that nice either. What we settled on in ABC was an interface that can be used in a fully, logically pure way but that encourages the writing of efficient queries. It does this by defining a sort order in two parts. The first (optional) part is a key which defines the main part of the sort sequence. The second (also optional) part is the fields used to sort duplicates within the first key. Combining this with some special technology within the view driver we have the panacea of full flexibility that is usually fast.

To put some meat on the bones; assume you have an invoice file containing a customer id, and an invoice date (amongst other things). There is a key on customerid. You want to list invoices in customer order with invoices for a customer listed in date order. You do an AddSortOrder(CustomerKey) and then an AppendOrder('INV:Dateordered'). The view driver will then read in the records for the first customer, sort them, then the second customer etc. Given that sorting is at least an NlogN process this "bucket sorting" can produce a massive time savings.

An additional tweak that should be available by C6 is that AppendOrder may start with a "*" character, meaning the specified order replaces the order specified by the key after and including the free element. This is useful for specifying range-limit information using a key but then ignoring any trailing key components.

Init PROCEDURE(VIEW V,RelationManager
RM,<SortOrder SO>)

Much of the init code is straightforward; note though that the order property may be set up in one of two ways. If passed in then that version is used, otherwise one is created. This allows a derived class to construct a larger queue (more fields) than the ViewManager requires while still having the ViewManager perform the administration required.

The order queue is central to the whole ViewManager operation and stores all the information pertaining to a given sort order. When the ViewManager is derived by a browse it stores all the information for one tab of the browse.

Note also the default values provided to the view driver to enable the SQL buffering technology.

The Init method also ensures the UseView method is called, for reasons I'll discuss under that method name.

Kill PROCEDURE,VIRTUAL

This is one of those messy little procedures that only really exists to ensure that there aren't any memory leaks.

Essentially Kill just loops through the records of the order queue, and for each element of that queue it cycles through each element of the filter queue freeing up each filter element. Then it disposes of the filter and order-clause queue and nulls out the free element (which is an any).

Finally if the order queue needs freeing (meaning it wasn't passed in from outside) then it's disposed of. Finally the order queue is freed.

UseView PROCEDURE,PROTECTED

UseView has a simple task, to call UseFile on all the files a view references. (UseFile technology is explained fully in my article on the FileManager class.) The requirement of calling UseFile is a little subtle.

Logically when the template uses a view (or a browse) it only knows about the primary file: the lookups are an implicit part of view functionality. But the implementation of the VIEW (within the Clarion language) has one or two legacy throwbacks. One of these is that the files have to be opened independently before the view will work. So the ViewManager "dresses" the view structure to tidy this up, making sure all of the underlying files have been used at an ABC level and are therefore likely to be open, thus satisfying the view.

A list of file references is available from the view driver itself. The FileManager reference is obtained from the internal lists so that UseFile can be called.

Summary

That takes care of the initialization and cleanup code. In Part II I'll look at the ViewManager methods used in typical browse operations.


David Bayliss is a Systems Architect for The TopSpeed Development Center. He has worked upon TopSpeed's compiler and was the chief architect of the Application Builder Classes.

Printer-friendly version

Reader Comments

To add a comment to this article you must log in.

 
 

Search

 

Advanced Search
Topical Index

Related Articles

Subscribe to
ClarionMag

One year: $159

(reg $189, save $30)

(includes all back issues since '99)

Renewals from $109

Two years: $249

(reg $289, save $40)

Renewals from $199

More Info

Subscribe Now!

ClarionMag Blog

RSS Feeds

Updates via Email

Enter your Email


Powered by FeedBlitz

Quick Links