FileManager Overview

Top  Previous  Next

The FileManager class declares a file manager that consistently and flexibly handles all the routine database operations for a given file. The file manager provides "setup" methods that let you describe the file and it's keys, as well as other methods to open, read, write, and close the file.

The file manager automatically handles autoincrementing keys, and, as implemented by the ABC Templates, handles some of the validity checks specified in the Clarion data dictionary, and some of the file handling settings specified in the data dictionary or application generator. However, even if you don't use the data dictionary, the application generator, or if you don't specify validity checks in your dictionary, the file manager can still competently and efficiently handle routine database operations for your files.

The FileManager class handles individual files; it does not handle referential integrity (RI) between related files. The RelationManager class enforces RI between related files.

Dual Approach to Database Operations

The FileManager methods that do standard database operations come in two versions--the plain (or interactive) version and the "Try" (or silent) version.

Interactive Database Operations

When any of these methods are called (Open, Fetch, Next, Previous, Insert, and Update), they may take several approaches and several attempts to complete the requested operation--including issuing error messages where appropriate. They may solicit information from the end user in order to proceed with the requested task. They may even terminate the application under sufficient provocation. This means the programmer can rely on the fact that if the method returned, it worked.

Silent Database Operations

When any of these methods are prepended with "Try" (TryOpen, TryFetch, TryNext, TryPrevious, TryInsert, and TryUpdate), the method makes a single attempt to complete the requested operation, then returns a success or failure indicator to the calling procedure for it to handle accordingly.

FileManager Relationship to Other Application Builder Classes

The FileManager relies on the ErrorClass for most of its error handling. Therefore, if your program instantiates the FileManager it must also instantiate the ErrorClass. See Error Class for more information.

Perhaps more significantly, the FileManager serves as the foundation or "errand boy" of the RelationManager. If your program instantiates the RelationManager it must also instantiate the FileManager. See Relation Manager Class for more information.

 

FileManager and Threaded Files

FileManager objects are designed to support multiple execution threads in a way that Clarion developers will recognize. That is, several MDI procedures may access the same file at the same time, with each procedure maintaining its own file buffer and file positioning information, so there is no conflict or confusion between the procedures.

To accomplish this desirable state of independence among several MDI procedures, you only need to add the THREAD attribute to your file declaration (see the Language Reference for more information), then instantiate a single global FileManager object for each file. This global object automatically handles multiple execution threads, so you can use it within each procedure that accesses the file. The ABC Templates generate exactly this type of code for files with the THREAD attribute.

When you want to access a file with a single shared buffer from multiple execution threads, you simply omit the THREAD attribute from the file declaration and, again, instantiate a global file-specific FileManager object within the program. This lets all your program's procedures access the file with a single shared record buffer and a single set of positioning information.

 

FileManager ABC Template Implementation

There are several important points to note regarding the ABC Template implementation of the FileManager class.

First, the ABC Templates derive a class from the FileManager class for each file the application processes. The derived classes are called Hide:Access:filename, but may be referenced as Access:filename. These derived classes and their methods are declared in the generated appnaBC0.CLW through appnaBC9.CLW files (depending on how many files your application uses). The derived class methods are specific to the file being managed, and they implement many of the file properties specified in the data dictionary such as access modes, keys, field validation and initialization, etc.

Second, the ABC Templates generate housekeeping procedures to initialize and shut down the FileManager objects. The procedures are DctInit and DctKill. These are generated into the appnaBC.CLW file.

Third, the derived FileManager classes are configurable with the Global Properties dialog. See Global Properties--File Control Options and Classes Options for more information.

Finally, the ABC Templates also derive a RelationManager for each file. These objects are called Hide:Relate:filename, but may be referenced as Relate:filename. The template generated code seldom calls the derived FileManager methods directly. Instead, it calls a RelationManager method that echoes the command to the appropriate (related files') FileManager methods. See Relation Manager for more information on the RelationManager class.

 

FileManager Source Files

The FileManager source code is installed by default to the Clarion \LIBSRC folder. The specific FileManager source code and their respective components are contained in:

 

ABFILE.INC

FileManager declarations

 

ABFILE.CLW

FileManager method definitions

FileManager Conceptual Example

The following example shows a typical sequence of statements to declare, instantiate, initialize, use, and terminate a FileManager object.

This example uses the FileManager to insert a valid record with an auto-incrementing key.

PROGRAM

 

INCLUDE('ABFILE.INC')                           !declare FileManager class

MAP                                             !program map

END

 

GlobalErrors ErrorClass                          !declare GlobalErrors object

Access:Client CLASS(FileManager)                 !derive Access:Client object

Init           PROCEDURE                         !initialize Access:File object

PrimeRecord    PROCEDURE,BYTE,PROC,VIRTUAL       !prime new record (autoinc)

ValidateField  PROCEDURE(UNSIGNED Id),BYTE,VIRTUAL    !validate a field

ValidateRecord PROCEDURE(<*UNSIGNED Id>),BYTE,VIRTUAL !validate all fields

             END

 

Client    FILE,DRIVER('TOPSPEED'),PRE(CLI),CREATE,BINDABLE,THREAD

IDKey      KEY(CLI:ID),NOCASE,OPT,PRIMARY

NameKey    KEY(CLI:Name),DUP,NOCASE

Record     RECORD,PRE()

ID          LONG

Name        STRING(20)

StateCode   STRING(2)

          END

         END

 

InsertWindow WINDOW('Add a new Client'),AT(,,159,73),IMM,SYSTEM,GRAY

       PROMPT('&Name:'),AT(8,20),USE(?CLI:Name:Prompt)

       ENTRY(@s20),AT(61,20,84,10),USE(CLI:Name),MSG('Client Name'),REQ

       PROMPT('State Code:'),AT(8,34),USE(?CLI:StateCode:Prompt)

       ENTRY(@s2),AT(61,34,40,10),USE(CLI:StateCode),MSG('State Code')

       BUTTON('OK'),AT(12,53,45,14),USE(?OK),DEFAULT

            END

 

CODE

GlobalErrors.Init                       !initialize GlobalErrors object

Access:Client.Init                      !initial Access:Client object

Access:Client.Open                      !open the Client file

 

IF Access:Client.PrimeRecord()          !prime Client record (autoinc)

 POST(Event:CloseWindow)                !if prime fails, close down

END

 

OPEN(InsertWindow)

 

ACCEPT

 CASE FIELD()

 OF ?OK

  IF EVENT() = Event:Accepted               !on OK button

   IF Access:Client.Insert() = Level:Benign !add the new Client record

    POST(Event:CloseWindow)                 !if add succeeds, close down

   ELSE                                     !if add fails

    SELECT(?CLI:Name:Prompt)                !select client name field

    CYCLE                                   !and start over

   END

  END

 OF ?CLI:StateCode                          !on StateCode field

  IF EVENT() = EVENT:Accepted

   IF Access:Client.ValidateField(3)     !validate the StateCode (3rd) field

    SELECT(?CLI:StateCode)               !if invalid, select StateCode field

    CYCLE                                !and start over

   END

  END

 END

 

Access:Client.Close                      !close the Client file

Access:Client.Kill                       !shut down the Access:Client object

GlobalErrors.Kill                        !shut down the GlobalErrors object

RETURN

 

Access:Client.Init  PROCEDURE

CODE

PARENT.Init(Client, GlobalErrors)        !call the base class Init method

SELF.FileNameValue = 'Client'            !set the file name

SELF.Buffer &= CLI:Record                !point Access:Client to Client buffer

SELF.AddKey(CLI:IDKey,'Client ID',1)     !describe the primary autoinc key

SELF.AddKey(CLI:NameKey,'Client Name')   !describe another key

 

Access:Client.PrimeRecord PROCEDURE       !called by base class Insert method

Result BYTE,AUTO

CODE

Result = PARENT.PrimeRecord()            !call base class PrimeRecord method

CLI:StateCode = 'FL'                     !default statecode to Florida

RETURN Result

 

Access:Client.ValidateField PROCEDURE(UNSIGNED Id)!called by base class ValidateFields

CODE                                     !and by this program too

IF ID = 3                                !validate the statecode (3rd) field

 GlobalErrors.SetField('StateCode')      !set field in case of error

 IF ~CLI:StateCode                       !if statecode is blank

  RETURN SELF.Throw(Msg:FieldNotInList)  !pass error to error handler

 END

END

RETURN Level:Benign

 

Access:Client.ValidateRecord PROCEDURE(<*UNSIGNED F>)!called by base class Insert

CODE

RETURN SELF.ValidateFields(1,3,F)             !validate all 3 fields