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

Ulm's Oberon Library:


Proxies - support of proxies for local objects


TYPE CreateProxyProc = PROCEDURE (VAR object: Services.Object;
                                  orig: Services.Object);
TYPE InitProxyProc = PROCEDURE (object: Services.Object;
                                orig: Services.Object);
TYPE Interface = POINTER TO InterfaceRec;
TYPE InterfaceRec =
         createProxy: CreateProxyProc;
         initProxy: InitProxyProc;

PROCEDURE Register(type: Services.Type; if: Interface); PROCEDURE Supported(type: Services.Type) : BOOLEAN; PROCEDURE GetSupportedBaseType(type: Services.Type; VAR baseType: Services.Type);

PROCEDURE CreateProxy(VAR proxy: Services.Object; orig: Services.Object);

PROCEDURE CreateUninitializedProxy(VAR proxy: Services.Object; orig: Services.Object); PROCEDURE InitializeAllInterfacesUpTo(proxy: Services.Object; type: Services.Type); PROCEDURE InitializeAllInterfacesBeyond(proxy: Services.Object; type: Services.Type);

PROCEDURE GetOrig(proxy: Services.Object; VAR orig: Services.Object);


A proxy object delegates all operations to another object, possibly after some filtering has taken place. Most proxy implementations just take care of one primary abstraction (i.e. an abstraction that is based upon the static type). A framework is needed to support extended abstractions. The delegation of secondary abstractions (i.e. abstractions based on dynamic type extensions as provided by Disciplines) is supported by Forwarders. A framework for delegations to remote objects is provided by RemoteObjects. This module provides the framework that supports the delegation of primary abstractions to local objects.

Assume a base type T, an extension of T named T1, which itself has been extended by T2. All of them come with their own set of operations. A proxy implementation for T1 is obviously aware of the operations of T. Hence, it can implement easily all delegating operations for T and T1. However, it cannot foresee the extension T2. Proxies allows proxy implementations to focus on just one abstraction layer (e.g. that of T1), assuming that another proxy module takes care of the base type (e.g. T) and other modules of the possible extensions (e.g. T2). Each proxy module has to provide two interface procedures to Register:

createProxy: PROCEDURE(VAR object: Services.Object; orig: Services.Object);
creates but does not initialize a proxy object of the associated type extension. Services.Init, however, needs to be called for object. The original object is provided through orig.

initProxy: PROCEDURE(object: Services.Object; orig: Services.Object);
initialize object at the associated abstraction layer. All interface procedures have simply to delegate the operation to the original object orig. Initializations according to the base types have already been performed.

Assume we have proxy modules ProxyT, ProxyT1, and ProxyT2. Then let us have a FilterT1 module that somehow filters all operations on T1 objects at the layer of T1 (not touching the operations at the T layer). Now, FilterT1 just needs to take care of the T1 operations. If the original object is an extension of T2, ProxyT and ProxyT2 will do the rest. ProxyT1 will be left out as this part is taken by FilterT1.

Note that none of the proxy modules can rely on an own static type extension even if they may have to create objects through the createProxy interface procedure. However, their delegating implementations have to work for anything that extends the type they are associated with. Hence, they will have to be based on disciplines (see Disciplines) instead of static type extensions if they need some bookkeeping. The link to the original target object does not need to be maintained, however, as GetOrig allows to retrieve it.

Supported tells if a given type has proxy support and GetSupportedBaseType returns the associated base type. Assume in the example above that the abstraction T2 is implemented by an extension T3. Then, if ProxyT, ProxyT1, and ProxyT2 registered themselves for T, T1, and T2, respectively, Supported would return TRUE for T3 and GetSupportedBaseType would return T2.

CreateProxy creates a proxy object proxy that delegates all operations to orig. Note that this creates a pure proxy object. None of the supported operations of the primary abstractions are filtered or changed in any way. The relation of proxy to orig is registered to Forwarders.

A filtering module that filters operations at some abstraction layer needs the initializations for all abstraction layers by the regular proxy modules but its own layer. This can be done by starting with CreateUninitializedProxy which returns a proxy object that has been created by the createProxy interface procedure of the most-extended proxy module. In the second step, all interfaces have to be initialized that are more basic than our abstraction layer using InitializeAllInterfacesUpTo which initializes all layers up to that of type which is included. In the third step, the initialization on the own abstraction layer has to be performed. Finally, InitializeAllInterfacesBeyond has to be invoked to initialize all interfaces for the extensions of type (excluding type). InitializeAllInterfacesBeyond also registers the relationship between proxy and orig to Forwarders.

GetOrig returns the original target object proxy is linked to.


Established proxy relations are announced to Forwarders which in turn registers the relationship with Resources.DependsOn to Resources. This causes all error events that are raised at the original object to be forwarded to the proxy object.


forward secondary abstractions through proxy objects
example for a proxy module at the Names abstraction layer
delegations to remote objects
example for a filtering module at the Names abstraction layer

Edited by: borchert, last change: 2004/09/22, revision: 1.1, converted to HTML: 2004/09/22

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