Philip Penn

Creating Reusable Components for a Data Browser Using MapObjects with Three-Tiered Architecture

Multitiered architecture provides a solid foundation for creating extensible, maintainable, scalable systems that can react to changes in business needs. In particular, the segregation of user interface, business, and data services at a logical level is key to achieving reuse. The MapObjects model provides functionality in all three tiers, making separation of its constituent parts especially important when integrating map components into an application. A generic data browser was created using a three-tiered architecture, wrapping up the extra functionality into components to maximize reuse.

The paper focuses on the experience of Convergent Group in creating a generic data browser for a public sector client. The application contains standard features, such as the ability to query and locate, as well as analytical capabilities. This functionality will be reusable between multiple projects using ActiveX technology.

MapObjects is a low-level toolkit, which does not provide all of the functionality required for the data browser. The Microsoft Windows paradigm of active selection was used as a user interface guideline. MapObjects does not contain business tier objects for dealing with spatial selection to provide a bridge between the search methods, TrackingLayer management (data services), and mouse clicks/zooming/highlighting (user interface services). Other significant additions included a component for dealing with user-defined views and storing and creating symbology.

This paper describes a strategy for identifying, designing, and creating COM-based components for a generic data browser using MapObjects and Oracle with Visual Basic/Visual C++ in a Windows NT 4.0 environment.


 

Introduction

This paper describes the identification and design of reusable components for a data browser using MapObjects with Visual Basic. To achieve reuse, the elements of a data browser had to be defined within the context of MapObjects functionality. The shortfall between MapObjects functionality and generic data browser functionality provided a basis for the components that needed to be built. The application was using SDE, so Oracle was available as an external database.

Convergent Group�s public sector client was looking at an initial delivery of a data browser, on top of which analytical and editing applications would be incrementally added. The primary goal was to provide a viewing tool for the client. The secondary objective was to create a suite of components that could be reused for other projects.

 

What is a Generic Data Browser?

A data browser defines the core of the GIS application. The main form and supporting code was not made into a component because it was likely that other projects would want the user interface to be configured differently. Any other projects could pick and choose which data browser services to use.

The following data browser services were grouped into subsystems:

Map Utilities

The Map control provides basic operations with regard to panning and setting extents. The aim was to have each event call only one line of a business object code, thus robbing the user interface tier of any map intelligence. If a feature required more than one line of code, then it was removed and put into a class. A data services class was not needed because MapObjects takes care of the database transactions for these operations, effectively forming the third tier. Functionality that involved manipulating the map was put into a clsMapUtilities class (see Figure 1). View extent management of toggling previous extents and map printing were delegated to separate classes.

Figure 1 MoExtra.dll

A design decision was made to include user interface references into two map utility components. Classes that contained user interface references were suffixed by UI. MapObjects provides functionality for printing the map, but leaves the programmer to deal with the orientation and the number of copies to print. It was assumed that most projects would want to use a common dialog to achieve this task. Secondly, a reference map subcomponent was created and bound to a form and the main map. This encapsulated the event code for performing a drag rectangle operation, as well as the subsequent change of the map reference extent.

The main disadvantage in this approach was that each project using the map utilities component would still have to code the user interface tier � and that code was likely to be very similar. The main form is not part of the component, and reuse is only achieved at the business services tier. The alternative � to create an OCX with event code � was seen as both overkill and too inflexible for the current scope.

User-Defined Views

Integral to a data browser is the ability to create, recall, and share views among different users. Since MapObjects does not currently provide support for performing these tasks, a component had to be designed. Oracle provided the multiuser support necessary to design a mechanism to allow shared, as well as private, views.

The application needed to reference SDE layer names, layer table names, and user layer names at a global level. These were stored in a Layers table.

Figure 2 ViewManager.dll

The View class in Figure 2 is the primary business object, representing the name, extent, visibility to other users, and layers (the order is remembered) of the given view. The Business Object Database Transfer class, clsViews, was responsible for updating, adding, and deleting entities in Oracle.

The ViewManager class is the top-level object, for which there is a global instance. It contained the views and methods for opening and closing the views. It did not deal with changing the layer order; this was achieved by setting the layers collection property on the view itself. These services were not included in the ViewManager class because it was tightly bound to the user interface.

Symbology

MapObjects provides basic symbology abilities, but it did not address the symbology specification for the project. In particular, the need to have both custom fill and custom outline is not provided by MapObjects, as well as more advanced fill and line patterns. MapObjects also does not provide a persistent storage mechanism that could be linked to the ArcInfo symbology sets.

Essentially, these problems were broken out into two areas: shared symbology layer specifications and MapObjects rendering (including custom line/polygon drawing).

Figure 3 LayerSymbols.dll

The Layer Symbology was stored in an Oracle table (Figure 3), where the specification could be used at run time by both MO and Map Production components of the project (designed with ODE). In this case, the clsLayerSymbols class represented the data services tier, being solely knowledgeable and responsible for database transactions. The symbols for each layer are obtained from the tables and stored in a collection of LayerSymbol classes. A layer can have more than one symbol attached to it (when used by the renderer), in which case, it had a controlling attribute.

 

Figure 4 MOSymbology.dll

The MOSymbology component was responsible for rendering all symbology in the data browser. The MOSymbology class (Figure 4) was defined in the ViewManager class and every layer called the GetLayerSymbology method to retrieve either the symbol or renderer associated with that layer. The MOLayerSymbols class creates the symbols from the symbols collection, attaching any custom line drawing methods and custom rendering, as required.

Figure 5 MapObjects Custom Line Drawing (Railroad)

Figure 5 shows the data browser using the symbology component to render true type markers and custom lines. The custom line drawing method was attached to a railroad layer. The line styles were exported from an ArcInfo line set.

 

Active Selection

The data browser, and all applications that used it, had to have the ability to select multiple entities. Central to this concept was the Microsoft Windows approach of selection by highlighting, with subsequent action performed on the selected entities. This is a workflow concept, so particular user interface components were not incorporated, as this would have tied certain toolbars and windows to the component. MapObjects does not currently provide objects to deal with selection in this manner. The main methods it provides are in the user interface tier (DrawShape, FlashShape) and the data services tier (Search methods). The objects of interest were the Map control, the Layers collection, and the TrackingLayer.

Figure 6 Active Selection performed by Query

The Map control in Figure 6 shows the result of the query function. All the entities found within the given search tolerance are highlighted. The currently active entity is highlighted in yellow with a diagonal cross fill to distinguish it from the rest of the selection. Entity selection can be performed by clicking, creating a polygon, or clicking and dragging a rectangle around the entities (as Windows does).

The data browser provides functionality for selection and makes the selection available to any application that wanted to use it. This was accomplished by designing a globally visible instance of a Spatial Selection class. This object contains a data service tier for retrieving the recordsets required for the selection. Querying functionality included the ability to query on one or all layers. The QuerySelection object (see Figure 7) was responsible for holding the results, including the currently selected entity. It also includes objects responsible for the selection, such as buffering and clicking and dragging a rectangle.

 

Figure 7 SpatialSelection.dll

The aim of the Spatial Selection component is to allow applications to use a common object to retrieve a map-based selection. Any application can call on the object to perform the following:

The Spatial Selection component (Figure 7) provides a bridge between the Map control, Layers collection, and TrackingLayer. The main challenges faced were in providing multiple selections through a global object and eliminating dependencies between the applications and the map.

The Crime Analysis application, for example, needed the following functionality:

Crime Analysis functionality was held in a class and therefore separate from the user interface level code. It calls the LocateTo method on the spatial selection object. This worked for functionality that involved no user interaction.

Selection by the user required user interaction (and therefore user interface services). Such a component had to be intertwined with the map control event code. The main form contained an application state to send the Spatial Select object a mouse down click. The Spatial Selection object eliminates the need for the Crime Analysis application to be dependent on the user interface (and therefore itself be non-reusable), but the Spatial Selection object needed a way to communicate with the Crime Analysis application (and any other application) that the selection was done. This was achieved by using events in Visual Basic. The class or form implementing the asynchronous spatial selection services contains a spatial selection object, registering it with the Spatial Selection class. When the spatial selection object has finished making a selection, it raises an event through any instances of the Spatial Alarm in the Spatial Selection object. Any instances of the Spatial Alarm class receive the event and allow processing to continue within the containing form. Any application could use this service as follows:

�This routine will return in the spatial alarm event

g_SpatialSelect.SelectPolygonUI

Public Event m_SpatialAlarm_SelectionFinished(bCanceled As Boolean)

�Do whatever we want with �g_SpatialSelect.SelectedRecords(ownerCrimeAnalysis)

To allow for multiple concurrent selections, the selected records were made a collection and indexed by owner. A decision was made to include user interface components for the selection. These were methods that would not have to be used should the user interface not wish to use them.

The TrackingLayerList class was responsible for holding the selection, which could be a record set or a shape, including the symbology for the selection. On the AfterTrackingLayerDraw map event, the Spatial Selection instance cycles through and draws each layer list, which was held as a collection and indexed by owner. In this way, a calling application could clear the selection by removing its entry from the TrackingListCollection.

Overall, the strategy worked well; although, the Spatial Select object was a global dependency for application classes. Extensive use was made of "friend" functions to hide methods and data from other components.

Non-Map Components

As a stand-alone Windows program written in Visual Basic, certain components were created to support the application.

The program needed the ability to store certain paths and state information. The system registry was chosen to store program settings because the registry handles the issue of default settings and user settings by its top-level keys (HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER). Through the use of subkeys, the registry provides a structured framework to store application settings. A new subkey was produced for each component. A globally visible SystemState object loaded all of the settings at start-up time and revealed the settings as properties.

All parts of the program needed access to certain generic, non-class functionality. Utilities, such as debugging, file, and string handling, were shared between all parts of the program. The Visual Basic Debug object was not used because it did not write to a file, and it was compiled out when making the executable. A debug module wrote to the file and was able to be compiled in for system integration testing and compiled out for the shipped product.

Another problem was that Visual Basic does not allow standard modules to be converted into DLLs. To work around this limitation, every module was turned into a class (using a wizard) with its instancing property set to GlobalMultiUse. Where shared data was needed, it was put into modules. This meant that the routines could be called with no declared prefix. This generic functionality was called BrowserCore.dll. All components and applications need to include this reference.

An all-encompassing error handler was designed to deal with application errors. Error messages were stored in a table, rather than a resource file, so that the window style, severity, and appropriate response could be encoded. System/application critical messages could "float" their way up to an event-level code. Although this system worked effectively, the final implementation proved to be too much overhead. Almost all of the errors encoded only had a standard message box with an OK button. Errors that required a different response could have been dealt with on-line for extra clarity.

Standard modules were also added to the project (see Figure 8).

Figure 8 DataBrowser.exe

These standard files included a database class, a main form, a main module, a global variable module, and a global definition module. The database class managed connections and access. In this way, the database access object can be switched easily. Global variables and definitions were stored in one location to improve their visibility from a file view. Although the modules are not strictly reusable, the structure is of use to any other project wishing to include the data browser components.

A main module was selected as a start-up module (as opposed to a form) to keep program initialization and termination in one file dedicated to the purpose.

Lessons Learned and Future Direction

The components described were successfully combined, along with an ODE map production component, to make the data browser. The creation of the components places particular emphasis on a rigorous design. The project used the MapObjects object diagram as a notation. At a minimum, business services must be separated from user interface services. Identification (and potential elimination) of dependencies was found to be of key importance. The three-tiered approach, used for the view manager and symbology, involved more design and coding than a two-tiered approach would have been, but it was found to be of significant benefit when certain applications switched from Access to Oracle for certain aspatial tables. A benefit not utilized in the current implementation is that the three tiers are currently logical and not physical. Scalability could have been achieved by splitting up the DLLs into ActiveX EXE servers. That is seen as a secondary benefit to maintainability, but it warrants further investigation for future clients. The inclusion of user interface services into a component produces a less flexible, reusable component. It should only be done when the control is simple and unlikely to change. The creation of OCXs was not considered due to time constraints. In the case of the Reference Map, for example, it would have made sense to have subclassed the Map control and included the functionality in the control. Some of the component functionality, such as buffering and symbology, are seen as desirable for a future MapObjects release.

 

ACKNOWLEDGEMENTS

I would like to thank the following software engineers for their contribution:

Derren Duburguet

John Stark

AUTHOR INFORMATION

Philip Penn


Software Engineer


Convergent Group


6200 S Syracuse Way, Suite 200


Englewood, CO 80111


(303) 741-8312


(303) 741-8401 fax


Philip.Penn@cvg-grp.com