9.4 The Proxy Pattern


The proxy pattern abstracts the true server from the client by means of a stand-in or surrogate class, providing a separation of a client and a server, and allowing specified properties of the server to be hidden from the clients.

9.4.1 Abstract

The proxy pattern decouples the true server from the client by means of a stand-in or surrogate class. There are a number of reasons why this may be useful, such as to hide some particular implementation properties from the clients and thus allow them to vary transparently to the client. For our purposes, the primary reason to use the proxy pattern is to hide from its client the fact that a server may be actually located in another address space. This allows the server to be located in any accessible location and the clients need not concern themselves with how to contact the true server to access required information or services.

9.4.2 Problem

The design of modern embedded systems must often be deployed across multiple address spaces, such as different processors. Many times such details are subject to change during the design process, or even worse, during the implementation of the system. It is difficult to hard-code the knowledge that a server may be remote because this may change many times as the design progresses. Further, the clients and servers may be redeployed in other physical architectures, using different communications media, and if the clients are intimately aware of these design details then porting the clients to the new platforms is made more difficult.

The two primary problems addressed by the proxy pattern are the transparency of the potential remoteness of the servers and the hiding and encapsulation of the means by which to contact such remote servers.

9.4.3 Pattern Structure

The proxy pattern, shown in Figure 9-3, clearly gets its lineage from the observer pattern. Indeed, the proxy pattern differs primarily in that it adds a proxy between the Abstract Client and the Abstract Subject classes.

Figure 9-3. Proxy Pattern

graphics/09fig03.gif

The pattern has two sides. In the first side, the Client-side Proxies subscribe to the Server-side Proxies, which publish the data under the command of the Concrete Servers. When the Concrete Servers call the send() operation, all the remote Client-side Proxies are notified of the new data.

On the other side, the Concrete Clients subscribe in turn to the Client-side Proxies, just as in the observer pattern the Concrete Clients subscribe to Concrete Servers. When these Client-side Proxies are notified of new data, they walk their notification lists to send the data to all their local subscribers.

Although the structure of the pattern emphasizes the exchange of Data objects, this is only one kind of service that can be performed via the proxy pattern. In fact, any service may be published by the server and accessed via the proxy classes, even if no data is actually exchanged.

9.4.4 Collaboration Roles

  • AbstractClient: The AbstractClient associates with the Client-side Proxy so that it can invoke the latter's subscribe() and unsubscribe() operations as necessary. It contains an accept() operation called to accept the information required by the subscription, the address (as a NotificationHandle), which is passed to the Client-side Proxy instance to which it connects.

  • AbstractProxy: The AbstractProxy class provides the general mechanisms to handle client subscriptions and data delivery. It aggregates, via composition, zero-to-many NotificationHandle objects (to notify the instances of its clients) and Data objects. It has two subclasses, one to service the application clients and one to service the application server. On the client side, the proxy acts in the same fashion as the AbstractSubject class in the observer pattern clients subscribe to receive the data that is subsequently pushed to them. On the server side, the Client-side Proxy subclass acts as a client to the Server-side Proxy subclass.

  • AbstractServer: The AbstractServer acts as a server of information desired by the AbstractClients. When appropriate, it pushes the data object to the Server-side Proxy by calling the latter's send() operation. There is only a single Server-side Proxy object for each AbstractServer. The AbstractServer is subclassed into ConcreteServer for the specific application classes.

  • Client-side Proxy: The Client-side Proxy is a specialized proxy that serves as the local stand-in for the ultimate server. Because its clients are local, it uses localized NotificationHandles so that when it receives updated information from its associated Server-side Proxy, it can notify its local clients. It must unmarshal the data messages and reformat the Data object into a local format from network format. It subscribes to the Server-side Proxy that ultimately provides the marshalled data from the AbstractServer. The Client-side Proxy usually subscribes to the Server-side Proxy immediately on its creation or as soon as its first client subscribes.

  • ConcreteClient: The ConcreteClient is an application-specific subclass of the AbstractClient. The pattern is applied by subclassing the AbstractClient and adding application-specific semantics into the new subclass.

  • ConcreteServer: The ConcreteSubject is an application-specific subclass of the AbstractServer class. The pattern is applied by subclassing the AbstractServer and adding application-specific semantics to the subclass.

  • Data: The Data class contains the information that the Abstract Server knows and the AbstractClient wants to know. The Data object containing the appropriate value may be shared with the clients by value since it must be at least potentially delivered to different address spaces.

  • LocalNotificationHandle: This subclass of the NotificationHandle class is used by the Client-side Proxy class. Most commonly, callbacks (pointers to the accept() method of the Client-side Proxy class) are used for the LocalNotificationHandle.

  • NotificationHandle: The NotificationHandle class stores information for each client so that the Abstract Proxy can notify its clients of the value stored in the Data class.

  • RemoteNotificationHandle: This subclass of the NotificationHandle class is used by the Server-side Proxy class to store the required information to contact its remote clients, instances of the Client-side Proxy class.

  • Server-side Proxy: The Server-side Proxy provides encapsulation of the AbstractServer from the communications media and protocols. It manages remote subscriptions from Client-side Proxy objects and notifies them when data is pushed to it by the AbstractServer. It is responsible for marshalling the information into a network or bus message and converting the data values into network format. The Server-side Proxy usually subscribes to the AbstractSubject immediately on its creation.

9.4.5 Consequences

The proxy pattern does a good job of isolating the subject from knowledge that the server may be remote. The advantage to this is that the clients are simplified, not having to deal differently with remote and local clients. The proxy pattern also encapsulates the knowledge of how to contact the servers into the proxy classes so that should the communications media change, fewer classes must be updated.

Because there are usually many fewer client proxy instances (one per data type per address space) than client instances, the traffic on the communications media is minimized. One message is sent across the bus or network for each proxy, rather than one per client. This reduces bus traffic, a common bottleneck in embedded and real-time systems. Bus traffic is reduced even further because of the use of a subscription policy, resulting in transmission of the data only when necessary, as opposed to polling for the data.

9.4.6 Implementation Strategies

On the local (client-proxy) side, the same implementation strategies used for the observer pattern apply here. The AbstractClient objects subscribe to the Client-side Proxies in the same way as in the observer pattern. For the remote (server) side, the implementation is generally highly protocol-specific. The Server-side Proxy marshals the messages from the AbstractServer and invokes the communications system to transmit them to its clients, the remote Client-side Proxy objects. The Server-side Proxy can do this because the Client-side Proxy objects subscribe to the Server-side Proxy.

Note that in this case, the Client-side Proxy objects must know a priori how to contact the Server-side Proxy for the desired information. Thus, this pattern is especially useful on asymmetric distribution architectures, that is, architectures in which the locations of objects are known at design time.

Note also that both the Client-side Proxy and the Server-side Proxy classes aggregate Notification Handle objects via composition. This latter class will typically be subclassed into "local" and "remote" flavors as an optimization. LocalNotificationHandles may be simple function pointers to the accept() method of the ConcreteClient class. Remote NotificationHandles must rely on the underlying transport protocol for message delivery.

9.4.7 Sample Model

The example for the proxy pattern is shown in Figures 9-4 and 9-5. The first figure shows the structure of the collaboration and the mapping of the objects onto the physical architecture. The latter figure gives an example of how such a system behaves.

Figure 9-4. Proxy Example Structure

graphics/09fig04.gif

Figure 9-5. Proxy Example Scenario

graphics/09fig05.gif

Figure 9-4 shows four nodes: the GasMixer, Safety, MedicalDelivery, and UserControl processors. The GasMixer contains the server, an object of class O2FlowSensor. This connects with a server-side proxy class O2 FlowServerProxy. This proxy aggregates Object IDs to use as addresses on the bus connecting the nodes running a custom communications protocol. This bus (shown as the heavy lines connecting the nodes) provides the physical means to deliver the messages among the objects running on different processors.

The GasMixerProcessor contains the O2FlowSensor, which acts as a server for the data. The O2FlowSensor invokes O2ServerProxy::send() to send the data to all the registered clients. This is done by walking the notification handle list (which holds Object IDs that the lower-level communications protocol uses for message delivery) and sending a message to each registered client (the O2FlowClientProxies).

There are four clients of the Flow data object: the SafetyMonitor running on the SafetyProcessor, the InspirationController and the Vaporizer running on the MedicalDeliveryProcessor, and the HistogramView running on the UserControlProcessor. Each processor containing at least one client also has a single O2FlowClientProxy instance to obtain the value from the O2FlowServerProxy.

The scenario in Figure 9-5 shows the clients subscribing to their client proxies and the client proxies subscribing to the server proxy. Later, when the O2FlowSensor receives an update, it invokes the O2FlowServerProxy::send() operation, which walks the NotificationHandle list (not shown to save space) and for each registered client proxy sends the data. In turn, the receiving client proxy walks its client list, for the ultimate delivery of the data.

Note: Although the send() operation walks the list of subscribers (RemoteNotificationHandles) in a serial fashion, the delivery of the messages is generally asynchronous, and you cannot determine the arrival order of the messages from the sending order. This is because the objects in different addresses usually operate in different threads, so relative order cannot be determined. That is why in the second update, a different deliver order is shown with respect to the delivery of the data to the concrete clients.



Real Time UML. Advances in The UML for Real-Time Systems
Real Time UML: Advances in the UML for Real-Time Systems (3rd Edition)
ISBN: 0321160762
EAN: 2147483647
Year: 2003
Pages: 127

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net