I'm drawing from the "Scenario" section of this chapter to provide a sample that includes a User Profile Service framework that resides in an ActiveX DLL, and an Excel client application that is a consumer of this framework. To recapitulate, this User Profile Service framework allows you to create user profile objects, as well as store and retrieve those objects to and from a repository (UserProfileRepository). What the Excel client does with this information is of no concern to the framework. The intended purpose of the framework is to provide a uniform approach to maintaining user profile settings of practically any variation. These settings are packaged in a UserProfile class object that is flexible enough to contain any amount of attributes of generally any type. The UserProfileRepository interface serves as a persistent object service for UserProfile objects.
Concrete classes inherit the UserProfileRepository interface, providing their own implementations that primarily involve storing and retrieving the state of a UserProfile object to and from a designated data source. A typical repository can store and retrieve settings to and from a SQL Server or Access database. A concrete repository class relies on interface inheritance to reuse the UserProfileRepository interface. As mentioned earlier, not all ActiveX-enabled programming languages support inheritance. Therefore, although such programming languages could be used to create client applications that are consumers of the User Profile Service framework, the languages could not be used without the inheritance language feature to extend the framework to support concrete repository classes.
Based on that premise, the User Profile Service framework sample I've included implements the Bridge design pattern, which essentially creates a bridge between the UserProfileRepository abstract interface and a concrete Excel workbook repository class that contains the implementation intended for that interface.
In this sample, the Excel client uses the User Profile Service framework to retrieve predefined user profile settings from an Excel workbook repository class object that are used for ODBC-based applications. The client's only function at this point is to create data source names (DSNs) in your operating system that can be referenced by ODBC-based applications. Careless programmers usually don't check for the existence of DSNs that are required for their ODBC-based applications to function. You can use this sample User Profile Service framework to guarantee that the DSNs required by your application do exist.
To run this sample,
If all is well, a workbook will appear in Excel that resembles Figure 5-3.
Figure 5-3. An Excel workbook used as a user profile repository.
On the worksheet under the area labeled User Profile Repository Information, you will find the user profile settings. On the right side of the worksheet under the Try Me section, click the button labeled Register DSN, which brings up the User Profiles dialog box. (See Figure 5-4.)
Figure 5-4. Dialog box containing user profile settings retrieved from the Excel workbook repository.
This dialog box uses the User Profile Service framework to display the various user profile settings by name that are located on the left side of the worksheet. Clicking the OK button will result in an attempt to create a DSN based on the currently selected user profile. You can see whether the attempt was successful in the User DSN tab of the ODBC Data Source Administrator dialog box. (You can invoke this dialog box by double-clicking the ODBC icon located in the Control Panel.) For instance, if you selected New_York, you would find a DSN entry in the dialog box labeled WTC. (See Figure 5-5.)
Figure 5-5. The ODBC Data Source Administrator dialog box serves as the user interface to the ODBC administrator.
This sample illustrates the advantages of a User Profile Service framework, but it is more important for us to understand how the framework is extended to support a repository workbook class created in Excel VBA by applying the Bridge design pattern. The following sections briefly describe all the Bridge design pattern participants that facilitate extensibility of the User Profile Service framework in this sample. Refer to the Bridge folder on the companion CD for a full disclosure of the source code.
The UserProfileRepository (abstraction) class is an abstract interface that defines how to persist UserProfile objects to a repository. Because the interface is abstract, it contains no implementation of its own. Concrete classes inherit this interface, providing unique implementation to store, retrieve, and remove user profiles from a particular data source. In the UserProfileFx ActiveX DLL project, I took these steps:
' Class Name: UserProfileRepository Option Explicit Public Function GetKeys(Keys() As String) As Long End Function Public Function GetUserProfile(Key As String) As UserProfile End Function |
The UserProfileRepBridge (bridge) class is a concrete class that inherits the UserProfileRepository abstract interface. The implementation of this class is special because, instead of persisting UserProfile objects to a particular data source, it delegates the task by publishing events to subscribing implementors. In the UserProfileFx ActiveX DLL project, I took these steps:
The resulting UserProfileRepBridge class looks like this:
' Class Name: UserProfileRepBridge Option Explicit ' Inherit the UserProfileRepository interface. Implements UserProfileRepository ' Define an event that corresponds to each property and method of ' the UserProfileRepository interface. Public Event GetKeys(Keys() As String, ByRef KeyCount As Long) Public Event GetUserProfile(Key As String, ByRef UP As UserProfile) ' Implement all properties and methods of the ' UserProfileRepository interface. In the implementation of each, ' publish the corresponding event. Private Function UserProfileRepository_GetKeys(Keys() As String) _ As Long RaiseEvent GetKeys(Keys, UserProfileRepository_GetKeys) End Function Private Function UserProfileRepository_GetUserProfile( _ Key As String) As UserProfile RaiseEvent GetUserProfile(Key, _ UserProfileRepository_GetUserProfile) End Function |
The WorkbookRepImpl (implementor) class is defined within Excel in VBA. The WorkbookRepImpl class is a concrete class that defines an Excel workbook repository implementation intended for the UserProfileRepository interface. WorkbookRepImpl subscribes to events published by a given UserProfileRepBridge class object. Event subscription is optional; therefore, as is the case in this sample, WorkbookRepImpl is subscribing to only two of the four events. Upon notification, its event handler is called automatically. Using the Visual Basic editor in the UserProfile Excel workbook project (UserProfile.xls), I took these steps:
Here is the resulting WorkbookRepImpl class:
' Class Name: WorkbookRepImpl Option Explicit Private WithEvents RepBridge As UserProfileFx.UserProfileRepBridge ' Attach Implementor to Bridge. Doing so will allow the ' Implementor object to subscribe to events published by the Bridge ' object. Public Sub Attach(upRepBridge As UserProfileFx.UserProfileRepBridge) Set RepBridge = upRepBridge End Sub ' Detach Implementor from Bridge. This results in an implicit ' unsubscribe of all events published by the Bridge object. Public Sub Detach() Set RepBridge = Nothing End Sub ' Implicitly subscribe to events GetKeys and GetUserProfile ' published by the Bridge object by defining the following event ' handlers respectively. ' Private Sub RepBridge_GetKeys(Keys() As String, KeyCount As Long) ' Excel implementation code located here. End Sub Private Sub RepBridge_GetUserProfile(Key As String, _ UP As UserProfileFx.UserProfile) ' Excel implementation code located here End Sub |