The ACE Service Configurator Framework
Sidebar 14: The ACE DLL Class
Dynamically linking and unlinking DLLs presents the following problems that are similar to those with native OS Sockets API in Chapter 2 of [SH02]:
– Non-uniform DLL programming interface that’s much less portable than the Socket API. Whereas the BSD Socket API is nearly ubiquitous, the API for linking and unlinking DLL varies greatly be-tween platforms.
– Unsafe types that invite errors and misuse because various DLL mechanisms return a weakly-typed handle that’s passed to DLL func-tions, such as looking up symbols and unlinking the DLL. Since there’s nothing that distinguishes these handles from other handles, however, their use is error-prone.
To address these problems, the ACE_DLLwrapper facade class abstracts the functionality necessary to use a DLL object itself, rather than dealing with procedural concepts and types. The ACE_DLL class eliminates the need for applications to use weakly-typed handles and also ensures re-sources are released properly on object destruction.
The interface ofACE_DLLis shown in the figure above and its key meth-ods are outlined in the following table:
ACE Class Description
ACE_DLL() open()
Opens and dynamically links a designated DLL.
˜ACE_DLL close()
Closes the DLL.
symbol() Return a pointer to the designated symbol in the symbol ta-ble of the DLL.
error() Return a string explaining which failure occurred.
are the same as those in the dynamic directive. The syntax is sim-pler, however, since the service object must be linked into the program statically, rather than linked dynamically. Static configuration trades flexibility for increased security, which may be useful for certain types of servers that must contain only trusted, statically linked services.
Remove a service completely: remove svc_name
The remove directive causes the ACE_Service_Configto query the
Section 4.4 The ACE Service Cong Class 115
ACE_Service_Repositoryfor the designated svc_name service. If it locates this service, it invokes its fini() hook method, which per-forms the activities needed to clean up resources when the service terminates. If a service destruction function pointer is associated with the service object, it’s called to destroy the service object itself. The
ACE SVC FACTORY DEFINE macro defines this function automatically.
Finally, if the service was linked dynamically from a DLL, it’s unlinked via theACE_DLL::close()method.
Suspend a service without removing it: suspend svc_name
Thesuspend directive causes theACE_Service_Configto query the ACE_Service_Repository for the designated svc_name service. If this service is located, its suspend()hook method is invoked. A ser-vice can override this method to implement the appropriate actions needed to suspend its processing.
Resume a service suspended previously: resume svc_name
The resume directive causes the ACE_Service_Config to query the ACE_Service_Repository for the designated svc_name service. If this service is located, itsresume()hook method is invoked. A service can override this method to implement the appropriate actions needed to resume its processing, which typically reverse the effects of the suspend()method.
Initialize an ordered list of hierarchically-related modules: stream svc_name’f’ module-list ’g’
The stream directive causes the ACE_Service_Config to initialize an ordered list of hierarchically-related modules. Each module con-sists of a pair of services that are interconnected and communicate by passingACE_Message_Blocks. The implementation of thestream directive uses the ACE Streams framework described in Chapter ??.
The complete Backus/Naur Format (BNF) syntax forsvc.conffiles parsed by theACE_Service_Configis shown in Figure 4.6. Sidebar 15 describes how to specifysvc.conffiles using XML syntax.
3. Utility methods. The key methods are outlined below:
Method Description
() .
116 Section 4.4 The ACE Service Cong Class
<svc-config-entries> ::= svc-config-entries svc-config-entry | NULL
<svc-config-entry> ::= <dynamic> | <static> | <suspend> |
<resume> | <remove> | <stream>
<dynamic> ::= dynamic <svc-location> <parameters-opt>
<static> ::= static <svc-name> <parameters-opt>
<suspend> ::= suspend <svc-name>
<resume> ::= resume <svc-name>
<remove> ::= remove <svc-name>
<stream> ::= stream <svc-name> ’{’ <module-list> ’}’
<module-list> ::= <module-list> <module> | NULL
<module> ::= <dynamic> | <static> | <suspend> |
<resume> | <remove>
<svc-location> ::= <svc-name> <type> <svc-initializer> <status>
<type> ::= Service_Object ’*’ | Module ’*’ | Stream ’*’ | NULL
<svc-initializer> ::= PATHNAME ’:’ FUNCTION ’(’ ’)’
<svc-name> ::= STRING
<status> ::= active | inactive | NULL
<parameters-opt> ::= STRING | NULL
Figure 4.6: BNF for theACE Service Config Scripting Language Sidebar 15: Using XML to Configure Services
Example
This example illustrates how to applyACE_Service_Configand the other classes in the ACE Service Configurator framework to configure a server that behaves as follows:
It statically configures an instance ofServer_Reporter.
It dynamically configures theReactor_Logging_Server_Adapter tem-plate from the Example portion of Section 4.2 into the address space of a server.
We then show how to dynamically reconfigure the server to support a dif-ferent implementation of a reactor-based logging service.
Initial Configuration. Themain()program below configures theService_
ReporterandReactor_Logging_Server_Adapterservices into an appli-cation process and then runs the reactor’s event loop.
Section 4.4 The ACE Service Cong Class 117
#include "ace/Service_Config.h"
#include "ace/Reactor.h"
int main (int argc, char *argv[]) {
ACE_Service_Config::open (argc, argv);
ACE_Reactor::instance ()->run_reactor_event_loop ();
return 0;
}
There are no service-specific header files or code in the main() program.
The genericity of this server illustrates the power of the ACE Service Con-figurator framework.
WhenACE_Service_Config::open()is called, it uses theACE_Service_
Config::process_directives()method to interpret the following svc.
conffile:
1 static Server_Reporter "-p $SERVER_REPORTER_PORT"
2
3 dynamic Server_Logging_Daemon Service_Object *
4 SLD:make_Server_Logging_Daemon() "$SERVER_LOGGING_DAEMON_PORT"
Line 1 Initialize the Server_Reporter instance that was linked stati-cally together with the main() program. The ACE STATIC SVC REQUIRE
macro used in the Service_Reporter.cpp file on page 107 ensures the Service_Reporterobject is registered with theACE_Service_Repository before the ACE_Service_Config::open()method is called.
Line 3–4 Dynamically link the SLD DLL into the address space of the process and useACE_DLLto extract themake_Server_Logging_Daemon() factory function from theSLDsymbol table. This function is called to obtain a pointer to a dynamically allocated Server_Logging_Daemon. The frame-work then calls the Server_Logging_Daemon::init() hook method on this pointer, passing in the "$SERVER_LOGGING_DAEMON_PORT" string as itsargc/argvargument. This string designates the port number where the server logging daemon listens for client connection requests. Ifinit() suc-ceeds, theServer_Logging_Daemonpointer is stored in theACE_Service_
Repositoryunder the name"Server_Logging_Daemon". TheSLDDLL is generated from the followingSLD.cppfile:
118 Section 4.4 The ACE Service Cong Class
typedef Reactor_Logging_Server_Adapter<Logging_Acceptor>
Server_Logging_Daemon;
ACE_SVC_FACTORY_DEFINE (Server_Logging_Daemon);
This file defines atypedef called Server_Logging_Daemonthat instanti-ates theReactor_Logging_Server_Adaptertemplate with the Logging_
Acceptorshown on page 50 of Section 3.3. The ACE SVC FACTORY DEFINE
macro is then used to generate themake_Server_Logging_Daemon() fac-tory function automatically.
The UML state diagram in Figure 4.7 illustrates the steps involved in configuring the server logging daemon based on the svc.conf file shown above. When theOPENevent occurs at run-time, theACE_Service_Config
Figure 4.7: A State Diagram for Configuring the Server Logging Dae-mon
class callsprocess_directives(), which consults thesvc.conffile.
When all the configuration activities have been completed, the main() program invokes theACE_Reactor::run_reactor_event_loop()method, which in turn calls theReactor::handle_events()method continuously.
As shown in Figure 4.7, this method blocks awaiting the occurrence of events, such as connection requests or data from clients. As these events occur, the reactor dispatches the handle_input() method of concrete event handlers automatically to perform the designated services.
Reconfigured Server. The ACE Service Configurator framework can be programmed to reconfigure a server at run-time in response to external events, such as the SIGHUP or SIGINT signal. At this point, the frame-work rereads its configuration file(s) and performs the designated direc-tives, such as inserting or removing service objects into or from a server, and suspending or resuming existing service objects. We now illustrate how to use these features to dynamically reconfigure our server logging daemon.
The initial configuration of the logging server shown above used the Logging_Acceptorimplementation from page 50 of Section 3.3. This im-plementation didn’t timeout logging handlers that remained idle for long periods of time. To add this capability without affecting existing code or theService_Reporterservice in the process, we can simply define a new
Section 4.4 The ACE Service Cong Class 119
svc.conffile and instruct the server to reconfigure itself by sending it the appropriate signal.
1 remove Server_Logging_Daemon 2
3 dynamic Server_Logging_Daemon Service_Object *
4 SLDex:make_Server_Logging_Daemon_Ex() "$SERVER_LOGGING_DAEMON_PORT"
Line 1 Remove the existing server logging daemon from theACE_Service_
Repositoryand unlink it from the application’s address space.
Lines 3–4 Configure a different instantiation of the Reactor_Logging_
Server_Adapter template into the address space of the server logging daemon. In particular, the make_Server_Logging_Daemon_Ex()factory function shown in the SLDex.cpp file below instantiates the Reactor_
Logging_Server_Adaptertemplate with theLogging_Acceptor_Exshown on page 58 of Section 3.4.
typedef Reactor_Logging_Server_Adapter<Logging_Acceptor_Ex>
Server_Logging_Daemon_Ex;
ACE_SVC_FACTORY_DEFINE (Server_Logging_Daemon_Ex);
The UML state diagram in Figure 4.8 illustrates the steps involved in reconfiguring the server logging daemon based on thesvc.conffile shown above.
Figure 4.8: A State Diagram for Reconfiguring the Server Logging Dae-mon
The dynamic reconfiguration mechanism in the ACE Service Configu-rator framework enables developers to modify server functionality or fine-tune performance without extensive redevelopment and reinstallation ef-fort. For example, debugging a faulty implementation of the logging service can simply involve the dynamic reconfiguration of a functionally equiva-lent service that contains additional instrumentation to help identify the erroneous behavior. This reconfiguration process may be performed with-out modifying, recompiling, relinking, or restarting the currently executing server logging daemon. In particular, this reconfiguration needn’t affect theService_Reporterthat was configured statically.
120 Section 4.5 Summary
4.5 Summary
This chapter described the ACE Service Configurator framework, which al-lows services to be initiated, suspended, resumed, and terminated dynam-ically and/or statdynam-ically. This framework helps to improve the extensibility and performance of networked application software by deferring service configuration decisions until late in the design cycle, i.e., at installation-time and/or at run-installation-time, without changing the application or server imple-mentations.
We applied the ACE Service Configurator pattern to enhance the net-worked logging service example described in previous chapters. The result is a networked logging service that can be configured and deployed in vari-ous ways via the ACE Service Configurator framework. The logging service provides a good example of why it’s useful to defer configuration decisions until run-time. The extensibility afforded by the ACE Service Configura-tor framework allows operaConfigura-tors and administraConfigura-tors to dynamically select the features and alternative implementation strategies that make the most sense in a particular context, as well as make localized decisions on how best to initialize them.
CHAPTER 5