
Extension and Java Implementation of the Reactor−Acceptor−Connector Pattern Combination* Alexandre Delarue Eduardo B. Fernandez Department of Ocean Engineering Department of Computer Science and Engineering Florida Atlantic University, Dania Beach, FL 33004 Florida Atlantic University, Boca Raton, FL 33431 [email protected] [email protected] Abstract Development of efficient client−server applications involves good knowledge of multithreading and network communication, domains often closely related to the operating system. Therefore, the reusability of components could be limited by some system specific techniques or limitations used in the design. To enhance the reusability and ease of use, it is then very important to decouple communication establishment and initialization from service use in a client−server application. In this way, upgrades are simplified and one can improve, for instance, the message format without knowing the way services work. On the other hand a developer in charge of maintaining or creating a new kind of service does not need to know how the connections are concretely established. The composition of the Reactor pattern [2] and the Acceptor−Connector pattern [1] provides a powerful pattern to handle concurrent requests delivered to a server with the benefit of the separation of concerns between connection establishment and service use. We tried to enhance the portability of this solution by considering a Java implementation of this composition. But the Java language presents significant differences with C++, which lead us to modify the original patterns designed by D. C. Schmidt and to introduce a new pattern based on the Reactor pattern to solve the encountered problems. Intent The Reactor−Acceptor−Connector design pattern offers two main features inherited from the Reactor [2] and the Acceptor− Connector [1] patterns. First, it handles service requests that are delivered concurrently to an application by one or more clients. Then, it decouples connection establishment and service initialization in a distributed system from the processing performed once a service is initialized. The Reactor is in charge of dispatching the events received on registered handlers. The connection establishment and initialization is made by the Connector and Acceptor, the service is then performed by the initialized service handlers using the connection created by the Acceptor and the Connector. Motivation The department of Ocean Engineering of Florida Atlantic University needed a way to access and process information collected by AUVs (Autonomous Underwater Vehicles). The accessibility of these data is provided by a specific server and the data are processed using some GIS (Geographical Information System) software. The possibility to decouple the connection establishment and service initialization from the processing performed is really important here. It provides the department a certain freedom to use another GIS software (GRASS [14] is actually used) whenever it is needed. The modularity of this pattern allow the use of the same strategy to establish connections and initialize services. The only change is the way of processing data in the service handlers. The use of a Reactor to handle the client requests provides a good way to dispatch the events, avoiding a multithreaded approach (one thread per service) to concentrate on simplicity (a multithreaded server involves synchronization, context switching...) and adaptability. Indeed the Reactor design pattern offers simple ways to add, improve a service or change message formats without modifying the existing services; moreover, it gives the opportunity to use multithreading when needed. * Copyright 1999, Alexandre Delarue & Eduardo B. Fernandez. Permission is granted to copy for the PLoP 1999 conference. All other rights reserved. 1 Applicability This pattern is more likely to be used in applications where the level of independence between the services and the connections must be high. This occurs when a software need to be adaptable to various network systems or to be easily upgraded by modifying the events model. The pattern also applies very well to systems where multithreading is inapplicable or should be limited (typically when one thread per service would lead to overuse of CPU resources due to excessive context switching). The use of the Java language to implement this pattern makes it also a great candidate for deployment of Intranet/Internet client−server applications via Java enabled web browsers. Structure Participants Fig.1 − Participants of the Reactor−Acceptor−Connector pattern combination Compared to the original Reactor pattern [2] and Acceptor−Connector pattern [1], two major modifications (Fig.1) are noticeable. The Synchronous Event Demultiplexer entity is not present and the Handle entity encapsulates all the network specific access methods. These choices will be discussed in the Implementation section because they are mainly due to the choice of Java for the implementation. 2 Handle: Encapsulates the resources that are managed by the OS for communication. The Handle offers all the methods to access the communication resources so that the Initiation Dispatcher can wait for events to occur on them and the Service Handlers can use them to communicate with their peers. The aim of the Handle here is to concentrate network specific techniques and therefore to provide a high level network access. Event Handler: Specifies an interface consisting of a hook method that abstractly represents the dispatching operation for service− specific events. This method must be implemented by application−specific services (Service Handlers). Initiation Dispatcher: Is in charge of registering, removing and dispatching the events that occurs on the registered handles by calling back application−specific Event Handlers. Several Initiation Dispatchers can be created both on the server or on the client side to share the management of the registered Event Handlers. Service Handler: Implements an application service, typically playing the client role, server role or both roles. It provides a hook method that is called by an Acceptor or Connector to activate the application service when the connection is established. The Service Handler uses the Handle component referencing to its peer for data−mode exchange with its connected peer Service Handler. Acceptor: Is a factory that implements a passive strategy to establish a connection and initialize the associated Service Handler. It incorporates a passive mode endpoint transport factory (Handle factory) that creates the network endpoints needed by the Service Handlers. Connector: Is a factory that implements an active strategy to establish a connection and initialize the associated Service Handler. It initiates the connection with a remote Acceptor and can use two connection modes to do so: a synchronous mode and an asynchronous mode. Collaborations Server side: 1/ Initialization phase The server creates an Initiation Dispatcher that will handle the events associated with this server. It has then to create one Acceptor for each type of service it is offering to its clients. Each Acceptor registers itself to the Initiation Dispatcher so that it can handle an OPEN_SERVICE event coming from a client on the Acceptor Handle. The server can then ask the Initiation Dispatcher to handle all the registered events by listening to the associated Handles. 2/ Service initialization The Initiation Dispatcher detects an OPEN_SERVICE event on the Handle of some Acceptor. It then calls the handle event method of this Acceptor for him to handle this particular event. The Acceptor creates a new service handler that will be in charge of processing the requests of the client. This Service Handler registers itself with the Initiation Dispatcher so that it could handle the following events: SERVICE_REQUEST, SEND_SERVICE_RESULT. Then it sends a SERVICE_READY event to its client peer Handle. 3/ Service use The Initiation Dispatcher detects a SERVICE_REQUEST event on the Handle of one Service Handler. As a result of this, it calls its handle event method. The service then processes the request and sends a SERVICE_RESULT_READY to its client peer. When the Initiation Dispatcher detects a SEND_SERVICE_RESULT on the Handle of the Service Handler, it calls back the handle event method of this service. This Service Handler can then send the results to the client peer. 4/ Service closure When the Initiation Dispatcher detects a CLOSE_SERVICE event on the Handle of a Service Handler, it calls its handle event method. The Service Handler has then to call the remove handler method of the Initiation Dispatcher to make it stop listening on its Handle for the events for which it had registered before. It can then close itself. Client side (synchronous connection mode): 1/ Initialization phase 3 The client creates an Initiation Dispatcher that will handle the events associated with this client. Then it has to create one Connector and one Service Handler (that will be in charge of requesting the server peer service handler) for each type of service needed. For this, the Connector generates an OPEN_SERVICE event and sends it on the Handle of the server Acceptor in charge of the desired service. In return, the Connector gets a connection end point that corresponds to the Handle of the peer Service Handler. It can then open the client Service Handler. This can then register itself with the Initiation Dispatcher for the following event types: SERVICE_READY, SERVICE_RESULT_READY.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages11 Page
-
File Size-