System and method for software component plug-in framework6996832Abstract The invention provides a software component plugin framework. The system described supports dynamic loading, instantiation, and unloading of interface implementations (plugin modules), together with encapsulation of these interface implementations. The many benefits provided by the invention include software reuse, interoperability and fast product development cycles. Claims What is claimed is: Description COPYRIGHT NOTICE [. . . ] indicates an optional item. <. . . > indicates a token which can be replaced by a real value conforming to the syntax specified. The value between <and > is often replaced with a plugin-specific name to retrieve plugin-specific functions. FIG. 2 shows a schematic of a system architecture in accordance with an embodiment of the invention. As shown in FIG. 2, the invention provides a dynamically configurable plugin engine, which in turn is part of a larger plugin framework 200 (hereinafter referred to as a PIF). In one embodiment, the PIF 200 comprises an engine 201, together with various plugin personalities and plugin extensions. These framework components allow a client application to access services in a manner that is transparent to the application invoking the service. Personalities 202 that can be used with the invention include such systems as TUXEDO, Jolt and AMS. These personalities allow a client application 206 to interact with the engine via a set of programming languages or attitudes 208. Attitudes include, for example, the C, OLE and Cobol attitudes offered by the TUXEDO personality. The personalities are plugged-in to the engine as a series of components, as are the services needed by the clients. Specialized plugins, often referred to as extensions 204, may similarly be plugged in to the framework, for example to act as managers or interfaces to a family or group of specialized services 205. As shown, the PIF enables the implementation and support of a component model architecture in which: A component is a set of software modules that are bundled together, and which provide implementations for a set of services specified by the corresponding interfaces. An interface is a contract about a set of services between the requesters (clients) and the providers (servers) of the services. This contract specifies a set of functions with the associated syntactical and semantical properties, for example the input/output parameters and the return values, etc. Components utilize a client/server relationship, and communicate with each other through interfaces. With this architecture, the engine 201 can be further visualized as shown in FIG. 3 as a pool of software components interacting with each other through a client-server relationship. A component 212 is considered a client when it invokes a service 220, 224 provided by another component, and a server 214, 215 when it provides a service being invoked by another component. The set of services offered by each server component can be accessed through a well-defined interface 216, 217. A server component can offer multiple sets of services through the corresponding interfaces which may be interrelated or not interrelated (independent from each other). An interface is a binding point between a client component and the server component. The client component need not know how these interfaces are implemented by a server component. In other words, the server component backing the interface is totally transparent to the client component. This means that an implementation 221, 222 (a plugin) of an interface 216 can be replaced by other plugins at run-time, without impacting the client application code. To a client, an interface may for example be a C language data type structure of which every member is a function pointer pointing to the plugin functions implementing the services defined by the corresponding interface. An interface is thus only a formal specification of a set of services until it (and its corresponding implementations or plugins) is registered and subsequently realized. As such, an interface has to be realized before its services can be invoked. The interface realization process consists of locating the specified implementation, loading it into the caller's address space, and populating an internal table of pointers with the addresses of the plugin functions implementing the services defined by the corresponding interface. Interface Definition One method of defining an interface is to use a standard specification such as the Object Management Group's (hereinafter referred to as OMG) Interface Definition Language (hereinafter referred to as IDL), or a subset of it. However, one can alternatively use any language which supports a "structure", "record", or an equivalent type of data structure with double-indirection support, (e.g. the struct command used in C or C++). The method of actually defining an interface is not necessary for an understanding of the present invention and can be left to the interface developer. The interface developer is however expected to provide the following software modules which are then linked by the clients and/or the plugins of that interface prior to run-time: Header Files: Both the client applications and the plugins use header files to define interfaces, function prototypes of the interface functions, and the macros for the invocations of various interface functions. These header files are included into the client application and the plugin's source code. Client stub files: The client application uses client stub files for invoking the interface functions. A client stub defines an interface as a set of language-specific data types and routines, one for each function (method) that is part of the interface. These client stubs are compiled and linked into the client application. Plugin skeleton files: A plugin uses the plugin skeleton files to map client invocations of interface functions to the actual function implementations in the interface implementation (i.e. the plugin). Interface Identity In one embodiment of the invention, every interface has a name that serves as the compile-time type in the code that uses that interface. These programmatic types are defined in header files provided by the interface developer. The programmatic name for an interface is only a compile-time type used within the application source code. Each interface also has a unique run-time identifier <interface id>, with the following syntax: wherein: It will be evident to one skilled in the art that the particular variable names and syntaxes given here are for exemplary purposes, and that the invention is not limited to the specific syntax described herein. In accordance with one embodiment, there is one universal namespace for recording <interface id>s in the engine PIF. Each <interface id> is unique within this namespace. In addition to <interface id>, every interface may also have a version associated with it, specified as two numbers, a <major version number> and a <minor version number>. The combination of an <interfaceid> together with a version uniquely identifies a particular version of an interface. Versions are used to indicate compatibility among interfaces, and particularly between releases of the same interface. A <major version number> change implies a different interface. Different major versions of an interface are not expected to be compatible with respect to each other. However, the same <major version number>s, but different <minor version number>s of an interface should be compatible in the sense that a version with higher <minor version number> should be downward compatible with the version with lower <minor version number>. Both the <major version number> and the <minor version number> can be given by a numeric string representing a number between 0 and 256. Each engine's personality and extension has a unique <component name>. An <interface name> should be unique within a component which owns it. The component provider (who may be a third-party vendor or developer) is responsible for assigning <interface name>s, <major version number>s and <minor version number>s to the interfaces which they provide. Implementation Identity In accordance with an embodiment of the invention every implementation of a supported interface has a unique implementation ID (implid) with respect to the interface it is implementing. This implementation ID has the following syntax: wherein: There is one universal namespace for recording <impl id>s in the engine PIF. Each <impl id> is unique within this namespace. Version Control Interface version compatibility is an important issue between an interface requested or invoked by a particular caller, and the interface implementation or plugin which backs or realizes the interface. In accordance with one embodiment of the invention, every interface has a version number that can be specified in terms of major and minor version numbers. A plugin is an implementation of a specific version of an interface. The following rules apply with regard to version compatibility between the interface being realized and the plugin being considered to back the interface during the realization process (the processing of —e—pif—realize( ) function): Each plugin has a run-time knowledge of the version of the interface for which it is providing an implementation. If the major version number of the interface which the caller is attempting to realize and the major version number of the interface which the specified plugin implements are different, then the interface and the plugin are not compatible and in this case the realization of the interface fails. If the major version number of the interface the caller is attempting to realize, and the major version number of the interface which the plugin specified implements are the same, then the following subset of rules apply: An interface with a higher minor version number is downward compatible (in terms of functionality, and function signatures) with interfaces with lower minor version number and identical <interface id>. An interface with a lower minor version number and identical <interface id> is a subset of an interface with a higher minor version number. During the realization process, the backing plugin (i.e., the one which is realizing the interface) must have a minor version number which is equal or higher than the minor version number of the interface being realized. Otherwise, the interface and the plugin are not compatible. The Vtbl returned by a plugin implementing an interface with a higher minor version number is allowed to grow only in a downward compatible way in terms of both size and content with the Vtbl of a plugin implementing the same interface, but with a lower minor version number. The term Vtbl used herein takes its common meaning and is a term known to one skilled in the art. The rules described above are given to illustrate a particular embodiment of the invention and particularly version numbers used within that embodiment. It will be evident to one skilled in the art that other rules can be substituted for or added to those shown above while remaining within the spirit and scope of the invention. Plugin Profiles PIF profiles provide a way of associating a PIF client (the caller of a PIF external interface function,whether it is an application process or a system process) with a set of PIF related attributes during run-time. A PIF client may want to use its own implementation for a specific interface or it may want to realize a different implementation. PIF profiles are identified by unique profile identifiers called <profile id>s. The syntax of a <profile id> is specified below. There is one universal namespace for <profile id>s in the engine PIF. Each <profile id> is unique in this namespace. The PIF can be configured to always search the profile <profile id> specified by an EV—PIF—PROFILE environment variable in <interface id> or <impl id>, before it searches for the default system-wide profile. A group of clients may be associated with the same profile and consequently refer to the same set of interface/implementation object attributes. A PIF client maybe associated with an existing PIF profile by setting the EV—PIF—PROFILE environment variable to the desired <profile id>. PIF Registry The PIF needs to locate the necessary plugin container, which can be a DLL (which contains the specified plugin), in order to load it into the registry Therefore it needs to know its image path and also other attributes about the interfaces and the interface implementations it is dealing with. To accomplish this, an embodiment of the invention uses a persistent storage based data repository for storing this kind of information. The PIF does not require a particular structuring for the persistent storage based plugin related information. Instead, the PIF describes this plugin information and specifies a set of command utilities for registering and unregistering plugins and for querying and/or updating the stored plugin information. Within this document, the data repository that is used for storing PIF related information is referred to as the "registry". In the registry, interfaces and interface implementations are identified by <interface id>s and <impl id>s, respectively. Both the interface, and the implementations backing it, have an associated set of attributes. In addition, an implementation is always associated with the interface it implements. Given a particular interface, there may be multiple implementations for that interface. An interface identifier <interface id> is an attribute of an interface implementation, identifying the interface this particular interface implementation implements. An implementation identifier <impl id> is an attribute of an interface it is associated with the implementation. In object-oriented terminology, the registry may be considered a persistent store for PIF related objects and their associated attributes. These PIF related objects and their attributes are described in table 1, table 2 and table 3. Table 1 lists some interface objects, table 2 implementation objects, and table 3 profile objects. It will be evident to one skilled in the art that other objects can be stored within the registry to supplement or replace those shown, while remaining within the spirit and scope of the invention.
Plugin Registration Before an interface implementation can be used (i.e., before it can be realized), it must be installed in the system and registered within the registry. Unregistration and/or uninstallation of the interface implementation is required to later remove all the relevant information from the registry. To accomplish these tasks, the PIF provides the following command utilities: epifreg ( ) for registering a plugin. epifunreg ( ) for unregistering a plugin. epifregedt ( ) for editing registry based PIF related information. The functions epifreg, epifunreg, epifregedt and the other functions described below, are given these function names for purposes of illustration. It will be evident to one skilled in the art that the invention is not limited to using the specific functions described herein. Dynamically Loadable Library (DLL) In one embodiment of the invention a dynamically loadable library (DLL) is used as the component server or container. Implementations of the interfaces (plugins) are contained inside DLLs. In accordance with one embodiment a DLL may contain only one plugin although their embodiments may support multiple plugin DLL's . A plugin may not span over multiple DLLs. A DLL may contain multiple plugins which may or may not be for the same interface. A DLL may contain a derived plugin, which implements only a subset of the functions which make up the corresponding interface, and which inherits the implementation of the remaining functions of the interface from another plugin. The PIF provides the following functions or services for loading and unloading a DLL to and from the caller's address space, and for getting the address of a function in a loaded DLL: —e—dl—load is used for loading an executable module into the address space of the calling process. —e—dl—unload is used for unloading a dynamically loadable library (DLL) module from the calling process' address space. This function also decrements a reference count associated with the specified library. —e—dl—getfuncaddr is used for getting the address of an exported dynamically loadable library (DLL) function given a function name. —e—dl—addref is used for incrementing the reference count associated with a DLL. These functions can be provided as a library tailored to each desired or supported personality. For example, for use with TUXEDO, the functions may be provided through a TUXEDO standard libgp library. Plugin Framework External Interfaces The PIF external interface comprises the following functions: —e—pif—realize( ) for realizing an interface and instantiating a plugin. —e—pif—dupref( ) for incrementing the reference count associated with an instance of a plugin (which can be used for lifetime control), or for duplicating a plugin instance. —e—pif—release( ) for decrementing the reference count associated with an instance of a plugin used for lifetime control. —e—pif—getinfo( ) for getting information about a plugin. —e—pif—iscompatible( ) for version compatibility checking. —e—pif—interception—seq( ) for getting the ordered sequence of interface pointers of the plugin instances in the fanout type interception sequence. —e—pif—this( ) for getting the address of the private data. Realization of An Interface FIG. 4 illustrates the flow of function invocation sequences during the interface realization process. Until it is realized, an interface is merely a specification of a set of function signatures with the associated behavioral semantics. In one embodiment, a number of implementations 238 can be stored in a container 240. In this example, a DLL file is used although other types of containers can serve this function. A client application 230 is used to register (and later to optionally unregister) these implementations within a framework registry 234. The registration process is accomplished by a series of routines epifreg, epifunreg, and epifregedt, described above. The names given herein for routines or functions are illustrative and are not required in all embodiments of the invention, but instead may be substituted or replaced with equivalent mechanisms and routines. Following the registration process, the registry thus contains a list of all current implementations. When a client application makes a request to use an implementation they must realize the interface. This is performed through an —e—pif—realize routine. Other routines, such as —e—pif—getinfo allow the client application to get additional information about the interface. A call to realize the interface is passed to a kernel portability layer 242. The kernel portability layer allows the PIF 200 itself to be independent of the operating system layer 246. The PIF translates the realize request from the client into a series of function requests 244 to the kernel portability layer to load the appropriate implementation container. The PIF also issues requests 248 to the appropriate container to instantiate a particular implementation (and later passes requests 250 to release that implementation). For an interface to be useful, an interface has to have a language binding, an implementation, and a well defined set of rules for interaction between the client and the implementation of the interface. This set of rules comprises the "interface realization protocol." The interface realization protocol encompasses rules governing client invocation, virtual function tables, plugin instantiation and reference counting. In accordance with an embodiment of the invention, the client of any particular interface must have a handle (pointer) to a newly created instantiation of a plugin backing the interface before it can invoke any of the functions of the interface. It acquires this handle for the interface by invoking the —e—pif—realize function, an example of which is shown in listing 1(TM32U is used to refer to an unsigned integer variable, other variable types can be used):
The pointer to the implementation id (implementation id pointer), hereinafter referred to as pImplId can be specified as either an <impl id> or a <selector>, or NULL. If pImplId is specified as NULL, then the <impl id> of the default implementation defined in the registry database (Defaultimpl attribute) is used instead. This default implementation is searched according to the search rules associated with the registry database, such as, for example, the first client's (caller's ) profile and then the system-wide profile for the interface ids. FIG. 5 shows a flowchart of a method used to read an implementation into a client's memory space. As shown in FIG. 5, in step 252 a set of framework interfaces is defined. In step 253 the client application is developed or otherwise instructed to use a particular interface defined within the framework. In step 254 the client application makes a request to actually use the interface within the plugin framework (PIF). A call is made to realize the interface (step 255). This results in the client receiving a pointer to the desired implementation (step 256), which it then uses in step 257 to locate the implementation, and to retrieve the implementation into local memory. The interface realization in this example involves only a single implementation (with no inheritance) and is further described in FIG. 6. In FIG. 6, a calling application (caller) 260 uses the PIF 262 to realize an implementation plugin A 264. The dashed lines in the Figure indicate the invocation sequence and the handles returned to various components during the realization of an interface. The solid lines in FIG. 6 indicate the relationships among the data structures involved in interface realization. The caller 260 issues a request 266 to the PIF 262 to realize an interface. The PIF uses this request information and the information stored in the registry to send an instantiate request 268 to a plugin A 264. The PIF uses the information stored within the plugins Vtbl 270, private data store 274, and per-instance data structure 272, to create a proxy Vtbl 276. A pointer 278 to the proxy Vtbl is then returned to the caller. The caller uses this pointer to thereafter communicate 280 with the interface and the implementation. Each of these processes is described in further detail below. As shown in FIG. 6, the handle returned (ip) is a pointer to a data structure in memory, called a Proxy Virtual Function Table (Proxy Vtbl). In one embodiment, the Virtual Function Table (Vtbl) is a C struct of function pointers pointing to the actual functions comprising the implementation for the interface being realized. Every plugin is required to maintain (e.g. allocating a memory block and populating it) its own Vtbl. Plugins are also responsible for managing per instance private data and plugin-wide struct —e—pif—plugin—info data structure. The PIF is responsible for presenting to a client a realized interface as a C struct, of which the members are pointers to functions implementing the function signatures which the interface specifies. As part of interface realization process, the PIF loads the container or DLL containing the target plugin for backing the interface, and then invokes <—ec—pif—instantiate>( ) function of the plugin, if it is available and registered. Otherwise, it invokes a DLL-wide —ec—pif—instantiate( ) function to instantiate an instance of the plugin. Both —ec—pif—instantiate( ) and <—ec pif—instantiate>( ) functions have the same function signature. Given a pointer to an <interface id> and a pointer to an <impl id>, they instantiate a plugin and return three handles: the address of the plugin's Vtbl; the address of the plugin instance specific private data; and the address of the plugin's —e—pif—plugin—info structure. The —e—pif—plugin—info structure contains information relevant to the implementation of the interface. In particular, an EF—PIF—SINGLETON flag indicates to the PIF that the implementation is a "singleton". When a singleton implementation is instantiated, new calls to instantiate the implementation result in a reference to the first plugin instance. The PIF may use this singleton indication to optimize reference handling for other —e—pif—realize( ) calls to this implementation (since the PIF is not required to call the —ec—pif—instantiate( ) function). If a particular implementation turns off this indication, then the PIF will always call the —ec—pif—instantiate( ) function every time the client realizes the implementation. Realization of a non-singleton plugin always results in a new plugin instance. Plugin Lifetimes The term Interface Lifetime Control is used herein to refer to the mechanism and the set of rules which are used to determine when to unload the container or DLL which contains the implementations of the interfaces that are currently in use. One of the goals of the invention is to make the caller or client immune to replacement of an interface's current implementation by another implementation. To the client, a component is the interfaces it supports. In most cases, the client does not know anything about the actual implementation of the interface provided by the component. Thus, the client can not directly control the lifetime of a DLL since different parts of a program may refer to different interfaces and/or multiple instantiations of the same interface supported by the DLL. In practice, a client will not want to unload the DLL when it is finished with one interface, but still using another interface. Determining when to release a DLL gets increasingly complicated with an increase in the complexity of the client application program. The PIF can be used to manage this lifecycle. To accomplish this, the PIF provides two functions, namely, —e—pif—dupref( ) and —e—pif—release( ) which can be invoked by PIF's clients for plugin lifetime control purposes. The PIF maintains a reference count for each plugin instance. When a client gets an interface pointer, the corresponding reference count is incremented by calling the —e—pif—dupref( ) function of the interface. When the client is finished using an interface, the reference count is decremented by calling the —e—pif—release( ) function of the interface. When all the reference counts of all the interfaces supported by a DLL falls to 0, the DLL is unloaded from memory. In addition to these two functions provided by the PIF, plugins may provide an implementation of the —ec—pif—destroy( ) function. The PIF invokes this function when the reference count for a plugin falls to 0. Effective use of a reference counting scheme imposes some rules on the parties involved, which are as follows: Every implementation of an interface should provide the —ec—pif—copy( ) function in support of the PIF's —e—pif—dupref( ) function. In one embodiment when the —e—pif—dupref( ) function is called with a EF—PIF—DEEP—COPY flag and the plugin is not a singleton, the PIF calls the plugin's —ec—pif—copy( ) function to obtain a copy of the private data of the plugin instance. Then, the PIF creates a new instance of the implementation. Each plugin container (DLL) also provides a —ec—pif—instantiate( ) for instantiating a plugin which the container contains. This function is invoked by the PIF during realization of an interface if the selected plugin does not provide its own <—ec—pif—instantiate>( ) function and does not set the value of its registry attribute EntryFunc to the name of its <—ec—pif—instantiate>( ) function. When calling member functions, the caller must include the interface pointer to the plugin instance (which is returned from the corresponding —e—pif—realize( ) function) as the first parameter. In accordance with an embodiment of the invention every plugin of a defined interface is required to obey the following rules:
Implementation Inheritance The PIF allows one interface implementation to inherit the implementation of a subset of interface methods or functions from another interface implementation within the same interface. This inheritance relationship between any two interface implementations of the same interface is specified with an InheritsFrom attribute. The InheritsFrom attribute is an attribute of the plugin which is inheriting and the value of this attribute identifies the interface implementation inherited from. This attribute takes an <impl id> as its value. The PIF may support single or multiple inheritance. With single inheritance the implementation that is inherited from may in turn inherit from another interface implementation by setting its InheritsFrom attribute to the <impl id> of the plugin it is inheriting from. The memory layout of the interface realization through implementation inheritance is described in FIG. 7. As shown in FIG. 7, dashed lines indicate the invocation sequence and the handles returned to various components during the realization of an interface; solid lines indicate the relationships among the data structures involved in interface realization. As before, a calling client 260 issues a request 266 to the PIF 262 to realize an interface. The PIF uses the information in the request and in the registry to send an instantiate request 268 to plugin A 264. Information from plugin A's vtable 270, private data store 274, and per-instance data structure 272 is used to populate part of the proxy vtable 276. This allows plugin A to fulfill a subset of the interface functions. The remaining interface functions are provided by a derived plugin B 284. Derived plugin B provides information from its Vtbl 290, private data store 294, and per-instance data structure 292, to populate the remaining functions in the proxy Vtbl. The caller then uses a pointer 278, as before, to communicate with the interface and the backing implementation via the proxy vtable. The following rules apply to the interface realization process: All of the plugins involved in the implementation inheritance or in the inheritance sequence should have a major version number that is equal to that of the interface being realized. At least one of the plugins involved in the implementation inheritance should have a minor version number that is equal to or higher than, that of the interface being realized. The minor version number of the derived plugin (the final output of implementation inheritance process) is that of the plugin with the highest minor version number among all the plugins involved in the implementation inheritance process. If any of the above rules are violated during the inheritance process, then the interface realization process may fail and an EE—PIF—VERSION—MISMATCH error value returned to the caller of —e—pif—realize( ). The Proxy Vtbl should not have NULL or invalid address valued entries. The specific rules described above are give for purposes of illustrating a specific embodiment of the invention, and to demonstrate the flexibility of the PIF system. These rules need not be implemented in whole or in part in order to operate the invention, and other rules may be substituted for those described above, while remaining within the spirit and scope of the invention. The PIF may also support interface inheritance the process of which operates similarly to that shown for plugin inheritance. Interceptors Interceptors provide a flexible means of adding services to a system. They allow the binding between the client and the target objects to be extended and specialized to reflect the mutual requirements of both. Interceptors can be logically thought of as being interposed in the invocation and response code paths between the client application making a request and the implementation of the object on which the request is made. As such, interceptors are the functions or methods of the configured interface implementations or plugins which provide the services being interposed. In one embodiment of the invention the engine supports two types of interceptors: Fanout type interceptors and Stack type interceptors. Interceptors are specified with a pair of attributes, namely, Interception Type and Interception Seq.. These attributes are associated with an interface implementation <impl id>. The InterceptionType attribute specifies the type of interception (either Fanout or STACK) while the InterceptionSeq attribute defines an interception sequence. An InterceptionSeq attribute specifies the intercepting plugins and their interception order. In one embodiment its value is a comma separated ordered set of <impl id>s, describing the order of the plugins whose methods are invoked in the order specified when the functions of the corresponding interface are called. Wherever a verb of the interface is referred to in a code path, the corresponding functions of the interface implementations specified in the data field of InterceptionSeq value are invoked in the order specified. Fanout Type Interceptors Fanout type interception is illustrated in FIG. 8. As depicted in FIG. 8, Fanout type interception can be implemented totally independently from the PIF. The PIF does not need to be aware of its existence and as far as the PIF is concerned, the interception sequence is no more than a group of plugins comprising the interception sequence specified with the InterceptionSeq attribute. In this approach however, the Fanout plugin needs to know how to access the registry to get the value of the corresponding InterceptionSeq attribute. This can be accomplished by exposing the registry application programming interface (API) or by using the PIF's help to support access by the Fanout type interceptors. In one embodiment the PIF may provide the necessary support with —ec—pif—instantiate( ) and —e—pif—interception—seq( ) functions. Referring again to FIG. 8, in this model of interception, the calling client or caller 302 invokes the methods of plugin A 304, but is not aware of the intercepting plugins 306, 308, 310, 312. During the instantiation of plugin A, the intercepting plugins as specified by the InterceptionSeq attribute of plugin A are also instantiated by the PIF and the sequence of ordered addresses of these instances of the intercepting plugins is passed to plugin A via —ec—pif—instantiate( ). Subsequent method invocations by the client or interface caller results in invocation of the corresponding methods of intercepting plugins in the order specified by the InterceptionSeq attribute. The key characteristics of this interception model can be specified as follows: Given that client invokes method X of plugin A (denoted as 303 in FIG. 8) method X of plugin A invokes method Xs of the intercepting plugins in the Fanout order specified by the InterceptionSeq attribute of plugin A as follows:
The methods of intercepting plugins return success or failure on function returns. The sequenced method invocation stops with the first method returning failure condition, and the status returned to the client. All of the plugins involved in the interception implement the same interface, i.e., their corresponding methods have the same signatures. Multiple occurrences of the same plugin are not allowed in an interception sequence. No intercepting plugin in a Fanout type interception sequence is allowed to be a Fanout type plugin or a stack-type plugin. A plugin is not allowed to be both a Fanout type plugin and a stack-type plugin. FanOut type plugins are not allowed to be derived (i.e., inheriting) plugins. The specific rules described above are give for purposes of illustrating a specific embodiment of the invention, and to demonstrate the flexibility of the PIF system. These rules need not be implemented in whole or in part in order to operate the invention, and other rules may be substituted for those described above, while remaining within the spirit and scope of the invention. Stack Type Interceptors Stack type interception is illustrated in FIG. 9. In the Stack type interception model shown in FIG. 9, the client 332 invokes the methods of plugin A 334, but is not aware of the intercepting plugins 336, 338, 340. The PIF is responsible for loading and instantiating the intercepting plugins, as specified by the relevant InterceptionSeq attribute, in addition to plugin A during interface realization, and for building and maintaining the interception sequence. Subsequent invocations of methods of plugin A by the client (interface caller) result in invocations of the corresponding methods of intercepting plugins in the order specified by the InterceptionSeq attribute. During the realization of an interface involving stack type interception sequence, the PIF passes the interface pointer to the next plugin in the interception sequence via <—ec—pif—instantiate>( ) function of each plugin in the sequence. The key characteristics of this interception model can be specified as follows: Given that client invokes method X of plugin A (shown as 333 in FIG. 9), method Xs of the intercepting plugins are invoked in the order specified by the InterceptionSeq attribute of plugin A as follows:
As with the Fanout type interceptors, with Stack interceptors, all of the plugins involved in the interception implement the same interface, i.e., their corresponding methods have the same signatures. Sequenced method invocation stops with the first method returning failure condition, and this status returned to the client. All the plugins involved in a stack-type interception sequence are required to be stack-type plugins except that the last intercepting plugin in the sequence is allowed to be a non-intercepting (neither Fanout type nor Stack-type) plugin. Multiple occurrences of the same plugin are not allowed in an interception sequence. A plugin is not allowed to be both a Fanout type plugin and a Stack-type (Stack-aware) plugin. Stack-type plugins are not allowed to be derived (i.e., inheriting) plugins. The specific rules described above are give for purposes of illustrating a specific embodiment of the invention, and to demonstrate the flexibility of the PIF system. These rules need not be implemented in whole or in part in order to operate the invention, and other rules may be substituted for those described above, while remaining within the spirit and scope of the invention. Process Threading In one embodiment of the invention, the PIF can serialize calls to a particular implementation's —ec—pif—instantiate( ), —ec—pif—copy( ), and —ec—pif—destroy( ) function, and make use of separate processing threads. This can contribute greatly to the overall performance of the system. Interface Function Utilities The following section illustrates various functions that are used with the PIF system to register implementations and to realize interfaces. It will be evident to one skilled in the art that additional or alternative functions can be used within the spirit and scope of the invention. —e—dl—load The —e—dl—load function maps the specified executable module into the address space of the calling process.
wherein —TCADEF is the optional ANSI definition of the engine context (typically used only for Tuscedo implementations). —e—dl—unload The —e—dl—unload function unloads a DLL:
The—e—dl—unload function unloads the specified library from the address space of the calling process. After this call, the specified handle is no longer valid, wherein: —e—dl—getfuncaddr The —e—dl—getfuncaddr function returns the address of the specified exported dynamic-link library (DLL) function:
The —e—dl—getfuncaddr function returns the address of the specified exported dynamically loadable library (DLL) function in pfa, wherein: —e—dl—addref The —e—dl—addref function increments the reference count associated with a loaded DLL:
The —e—dl—addref increments the reference count of the DLL specified by dllhandle. It should be called for every new copy of a pointer to an instant of a plugin, wherein: —ec—pif—instantiate The —ec—pif—instantiate function instantiates a plugin:
The —ec—pif—instantiate( ) function is a container-wide, default plugin instance instantiate function (<—ec—pif—instantiate>( )), invoked by the Plugin Framework (PIF) during the realization of an interface (i.e. as a result of a client invoking —e—pif—realize( )). It is implemented by a plugin implementer and is invoked only if plugin specific instantiate function is not available. If a plugin specific <—ec—pif—instantiate>( ) function is provided, then this function is invoked rather than the DLL-wide —ec—pif—instantiate( ) function. The plugin specific <—ec—pif—instantiate>( ) function has the same function signature as that of —ec—pif—instantiate( ) function, wherein: The —ec—pif—instantiate( ) function, given a pointer to an <interface id>, version of the interface and a pointer to an <impl id>, instantiates a plugin implementing the interface being realized and returns a set of handles about the plugin and the instance of the plugin being instantiated in a memory block pointed to by pI. The version specifies the version of the interface whose <interface id> is pointed to by pIId. The pInterceptionData points to a in-core data structure of data type struct e—pif—interception—data defined as follows:
The pointer pI points to a memory block of data type struct e—pif—instance—handles defined as follows:
In the pInterceptionData structure the pVtbl contains the address of the Vtbl of the plugin being instantiated. The pPrivData contains the address of the private data of the instance of the plugin being created. pPluginInfo contains the address of the memory block of type struct —e—pif—plugin—info, containing plugin information specific to the plugin being instantiated. It is the responsibility of the plugin to populate the fields of this structure. The struct —e—pif—plugin—info is declared as follows:
The —e—pif—plugin—info structure contains information relevant to the implementation of the interface. The m—flags field defines flags set by the implementation and interpreted by the PIF. In one embodiment of the invention, the following flags are defined: EF—PIF—SINGLETON—signal or flag that the implementation is a singleton object EF—PIF—STACK—signal that the implementation is a stack-type intercepting plugin EF—PIF—FANOUT—signal that the implementation is a Fanout type intercepting plugin EF—PIF—CONCURRENCYAWARE—signal that the implementation (whether it is a derived implementation or a head of a Fanout or STACK type interception sequence) is concurrency aware The EF—PIF—SINGLETON flag is a hint to the Plugin Framework to indicate whether the implementation is a singleton. When a singleton implementation is instantiated, new calls to instantiate the implementation result in a reference to the first plugin instance. The PIF can use this hint to optimize reference handling for other —e—pif—realize( ) calls to this implementation (in that the Plugin Framework is not required to call the —ec—pif—instantiate( ) function). The flags specified by m—flags field are not mutually exclusive. EF—PIF—QUERY is one example of such a flag. When it is set, —ec—pif—instantiate( ) populates pVtbl and pPluginInfo fields of struct —e—pif—instance—handles pointed to by pI without instantiating the plugin. —e—pif—realize The —e—pif—realize function realizes an interface:
The —e—pif—realize function realizes an interface specified by pIId and version by instantiating the interface implementation specified by pImplId. The client of an interface should have a pointer to newly created instantiation of a plugin backing the interface before it invokes any function of the interface. It acquires this handle for the interface by invoking the —e—pif—realize function. The pImplId is either the <impl id> of or a <selector> for the plugin to be instantiated. If pImplId is specified as NULL, then the default implementation (DefaultImpl) for the interface <interface id> is loaded to back the interface. If no default implementation for the interface is set, then a registered implementation with the equal major version number to that of the interface (being realized) and the highest minor version number is loaded to back the interface subject to the version control rules specified below: The major version number of the target plugin should match the major version number of the interface. Otherwise, the interface being realized and the target implementation are not compatible. The minor version number of the target plugin should be equal to or higher than that of the interface being realized. Otherwise, the interface and the target implementation may not be compatible. If the target implementation is inheriting from other plugins, all of the plugins in the inheritance sequence should have a major version number equal to that of the interface being realized. If the target implementation is inheriting from other plugins, at least one of the plugins in the inheritance sequence should have a minor version number that is equal to or higher than that of the interface being realized. If pImplId is specified and EF—PIF—EXACT—MATCH flag is set, then the plugin specified by pImplId is loaded subject to version control rules as specified above. If it is not registered (i.e., not found), then this function fails and returns an EE—PIF—NOT—REGISTERED error value is returned. If pImplId is specified, but not registered or found, and the EF—PIF—EXACT—MATCH flag is not set, then the system attempts to locate the default implementation for the interface. If the default implementation is not compatible or not found, then the system will attempt to locate a compatible implementation with the highest minor version equal to or greater than the value specified in the version argument. If a compatible implementation does not exist, then the function fails, returning an EE—PIF—NOT—REGISTERED error. The specified plugin is then located according to the search rules associated with the registry such as, for example, first the client's (caller's) profile and then the system-wide profile for the interface ids. The data point to data passed to the plugin from the caller, and datalen specifies the length of the buffer pointed to by data. —e—pif—dupref The —e—pif—dupref function increments the reference count associated with a loaded plugin instance or duplicates a plugin instance:
The —e—pif—dupref increments the reference count of the plugin instance pointed to by pI and duplicates the address of the plugin instance into ppdup. It should be called for every new copy of a pointer to an instant of a plugin. The flag may include EF—PIF—DEEP—COPY, which if specified, causes the Plugin Framework to create a duplicate copy of the instance specified by pI and return an interface pointer to the duplicate copy into ppdup. The duplicate instance has its own memory block for its private data (if such exists), life control and unique interface pointer. —e—pif—release The —e—pif—release function decrements the reference count associated with a loaded plugin instance:
The —e—pif—release decrements the reference count of the plugin instance pointed to by interface pointer pi. If the reference count of the specified plugin instance falls to 0, then the plugin instance is destroyed. —e—pif—iscompatible The —e—pif—is compatible function checks if a specified interface version is supported by a plugin instance:
The —e—pif—iscompatible checks to see if the plugin instance specified by pI is compatible with the interface version specified by version. —e—pif—interception—seq The —e—pif—interception—seq function returns an ordered sequence of addresses of the instances of the plugins in the interception sequence:
There may be only one plugin in the sequence, Regardless, the —e—pif—interception—seq returns the addresses of the instances of the intercepting plugins in the calling sequence relative to the plugin instance specified by pI into an in-core data structure of data type struct —e—pif—interception—data pointed to by *ppInterceptionData. The data structure struct e—pif—interception—data is defined as follows:
If the caller is a fan-out type plugin, then n ordered sequence of the addresses of the Fanout intercepting plugin instances which make up the interception sequence for the Fanout plugin is returned into an array *fanout—interception—seq. The fanout—interception—seq—len variable specifies the number of addresses in this array. In the case of stack type intercepting plugins, the address of the next plugin instance in the calling sequence is returned into *next—ip. If the plugin instance specified by pi is the last plugin instance in the interception sequence, then a NULL is returned in *next—ip. —e—pif—this The —e—pif—this function is used to return the address of the private data area:
The —e—pif—this returns the address of the private data area of the plugin instance specified by pI. The pVtbl handle points to the plugin specific Vtbl. This is the same Vtbl whose address is returned from <—ec—pif—instantiate>( ) function during the creation of the instance of the plugin. —e—pif—getinfo The —e—pif—getinfo function is used to get information about a loaded plugin:
The —e—pif—getinfo gets information about a plugin instance specified by pi. This information is returned into the —e—pif—plugin-info-public structure pointed to by pInfo:
The m—flags field defines flags set by the implementation and interpreted by the PIF, and include EF—PIF—SINGLETON, EF—PIF—STACK, EF—PIF—FANOUT, and EF—PIF—CONCURRENCYAWARE, all of which are described in further detail above. Concurrency awareness always imply composite behavior—if the plugin is a derived plugin or a head of an interception sequence, then this means that all of the plugins involved in the composition are concurrency aware and that if one of the components does not support concurrency, then the composition is not concurrency aware. Consequently, in this case the concurrency aware flag is not returned. The flags argument specifies optional flags, for example the EF—PIF—DETAILEDINFO flag. If it is specified, —e—pif—getinfo( ) returns detailed information about the plugin specified. If the plugin specified is a derived implementation, then the information about all the implementations involving in the derivation of the plugin are returned, starting from the most derived implementation. If the plugin specified is the head of a Fanout type or STACK type interception sequence, then the information about all the plugins involved in the interception sequence is returned, starting from the plugin specified (head of interception sequence) followed by the intercepting plugins, left-to-right in case of Fanout type, and top-down in case of STACK type. —ec—pif—destroy The —ec—pif—destroy function is used to destroy a plugin instance:
The —ec—pif—destroy releases the plugin instance specific system resources specified by pIhandles. The pIhandles points to a memory block of data type struct —e—pif—instance—handles defined as follows:
wherein the pVtbl contains the address of the Vtbl of the plugin instance, and pPrivData contains the address of the private data of the plugin instance being destroyed. If no private data is used by the plugin instance, then the value of pPrivData is set to NULL. pPluginInfo contains the address of the memory block of type struct —e—pif—plugin—info, containing plugin information specific to the plugin instance. This function is only invoked by PIF when the reference count associated with a plugin instance falls to 0. —ec—pif—copy The —ec—pif—copy function creates a duplicate copy of a plugin instance:
The —ec—pif—copy creates a duplicate copy of plugin instance private data specified by pIhandles and returns pointers to duplicate copies in the data structure pointed by pIhandles. The pInterceptionData points to an in-core data structure of data type struct e—pif—interception—data (defined above), while the pIhandles points to a memory block of data type struct —e—pif—instance—handles (also defined above). The pVtbl is a pointer containing the address of the Vtbl of the plugin instance whose private data are being duplicated. pPrivData is a pointer containing the address of the plugin instance private data. If no private data are used by the plugin instance, then NULL is returned. The pPluginInfo pointer contains the address of the memory block of type struct —e—pif—plugin—info, containing plugin instance specific information which is declared as follows:
The —e—pif—plugin—info structure contains information relevant to the implementation of the interface. The m—flags field defines flags set by the implementation and interpreted by the PIF. Flags may include EF—PIF—SINGLETON, EF—PIF—STACK, EF—PIF—FANOUT, and EF—PIF—CONCURRENCYAWARE /*, all of which are described in further detail above. epifreg The epifreg function or command registers a plugin implementation, and uses the following syntax:
The epifreg function can take a variety of options as indicated above, wherein the options have the following meaning: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
