Oberon || Library || Module Index || Search Engine || Definition || Module

Ulm's Oberon Library:


ModularizedStructures - distribute graphs of persistent objects across multiple byte sequences


TYPE ObjectTable = POINTER TO ObjectTableRec;
TYPE ObjectTableRec = RECORD (Disciplines.ObjectRec) END;

CONST corruptedInput = 0; readFailed = 1; CONST typeGuardFailure = 2; unknownObject = 3; CONST writeFailed = 4; errors = 5; TYPE ErrorCode = SHORTINT; (* corruptedInput ... *) TYPE ErrorEvent = POINTER TO ErrorEventRec; TYPE ErrorEventRec = RECORD (Events.EventRec) s: Streams.Stream; code: ErrorCode; otype, guard: Services.Type; modname, name: ConstStrings.String; END; VAR error: Events.EventType; VAR errormsg: ARRAY errors OF Events.Message;

PROCEDURE CreateTable(VAR table: ObjectTable); PROCEDURE Add(table: ObjectTable; object: PersistentObjects.Object; modname, name: ConstStrings.String); PROCEDURE Insert(table: ObjectTable; object: PersistentObjects.Object; modname: ConstStrings.String; VAR name: ConstStrings.String); PROCEDURE Lookup(table: ObjectTable; modname, name: ConstStrings.String; VAR object: PersistentObjects.Object) : BOOLEAN; PROCEDURE GetObjects(table: ObjectTable; it: Iterators.Iterator); PROCEDURE InTab(table: ObjectTable; modname: ConstStrings.String) : BOOLEAN;

PROCEDURE Init(s: Streams.Stream; modname: ConstStrings.String; table: ObjectTable); PROCEDURE GetParams(s: Streams.Stream; VAR modname: ConstStrings.String; VAR table: ObjectTable);

PROCEDURE Read(s: Streams.Stream; VAR object: PersistentObjects.Object) : BOOLEAN; PROCEDURE GuardedRead(s: Streams.Stream; guard: Services.Type; VAR object: PersistentObjects.Object) : BOOLEAN; PROCEDURE Write(s: Streams.Stream; object: PersistentObjects.Object; modname, name: ConstStrings.String) : BOOLEAN;


ModularizedStructures allows to store and restore graphs of persistent objects across multiple byte sequences. This works by associating objects with modules that correspond to separate byte sequences and giving objects names that may be used to reference objects in foreign modules. These graphs may contain cycles as ModularizedStructures is based upon LinearizedStructures.

Graphs are written module-wise: Open an individual stream for each module, call Init for it, and invoke Write for a root object of that module. Root objects have the property that all other objects of that module can be reached from them without crossing module boundaries.

On reading, modules have to be read in topological order by invoking Read or GuardedRead for each of the root objects on each individual stream representing a module. An object table allows to resolve references across module boundaries by storing all objects read so far by their module and object names.

Note that ModularizedStructures does not store any information (using PersistentDisciplines or whatever) about module and/or object names at the objects itself. Instead these names must be explicitly passed to Write, and the reading marshalling procedures are expected to add objects to the object table. This avoids redundancy and gives more flexibility in allowing objects to be used in more than one context of ModularizedStructures. It is recommended to put support for this in an application-dependent persistent object type. An example for this is CompilerObjects.

Not all objects belonging to a modularized graph need to be named and read or written using ModularizedStructures. This is necessary only for objects that are possibly referenced across module boundaries. Objects that are referenced by multiple modules but not saved and restored using ModularizedStructures will be duplicated.

CreateTable creates an object table that stores persistent objects by their module and object name. Object tables are later associated by Init with a stream that represents a module, and used (but not maintained) by Read and GuardedRead.

Add adds object to table with the given module and object name. Module names do not have to be registered before, they come into existence when they are mentioned first. Insert works like Add but generates an unique name for it. Lookup allows to access objects of a table by their module and object name. GetObjects returns an iterator that allows to iterate through all objects of an object table. InTab returns TRUE if objects of module modname are included in the table.

Init associates a stream with a module name and a table. There is only one such association active for a stream and multiple calls of Init allow to change an association. Note that the object table parameter may be NIL if neither Read nor GuardedRead will be called for that stream. GetParams returns the parameters passed earlier to Init. Note that GetParams must not be called if Init has not been called before.

Read and GuardedRead work like their counterparts in LinearizedStructures but support references across modules if referenced objects are to be found in the object table associated with s. Write writes a reference of object (if modname is non-NIL and not equal to the module associated with s), or the object itself using LinearizedStructures otherwise.


In addition to the error events generated by LinearizedStructures, PersistentObjects, the marshalling procedures in use, and the underlying stream, ModularizedStructures may return following error codes for its error events:
Read or GuardedRead found input that was not generated by Write.
One of the reading operations of NetIO failed (most probably due to an unexpected end of input).
The type guard of GuardedRead failed.
An object reference was found that is not included in the object table.
The write operation failed due to a failure returned by NetIO or LinearizedStructures.


support of graphs of persistent objects
interface of persistent objects

Edited by: borchert, last change: 2000/04/27, revision: 1.1, converted to HTML: 2000/04/27

Oberon || Library || Module Index || Search Engine || Definition || Module