Extending ArcObjects  

Geodatabase modeling with UML

This topic is relevant for the following:
Product(s): ArcGIS Desktop: All
Version(s): 9.0, 9.1, 9.2
Language(s): VB6, VC++
Experience level(s): Intermediate to advanced



In this section

  1. Geodatabase modeling
  2. Creating UML object models for custom classes
  3. Generating code
  4. Generated code

Geodatabase modeling

The geodatabase data model is an object-oriented data model for geographic data. To create blueprints of the objects, their relationships, and their behavior, you can use UML, a graphical modeling language. Utilize the CASE tools to create the storage medium (geodatabase schema) and object behavior (custom features and class extensions).

This appendix explores the concepts involved in modeling object behavior using UML and the Code Generation Wizard.

NOTE: CASE tool functionality does not apply to ArcView licenses.

Geodatabase modeling with UML

UML is the universal language of object modeling. With UML you can build object models that help you and others better understand the system in development. The more complex a system is, the more difficulty you will have understanding it. Modeling helps you understand such complex systems.

Using UML to model geodatabase structure

Using UML, you can create object models that include geodatabase elements. In the same way that the ArcGIS object model diagrams help you understand ArcObjects, modeling geodatabase elements using UML lets you clearly visualize the structure and behavior of your system. For example, you can easily see what feature classes are involved in a geometric network, how features may be associated through relationship classes, or what services a custom feature provides.

These elements may be subdivided into structural elements, parameterized elements, and custom behavior elements, summarized in the table below.

Structural Elements Parameterized Behavior Custom Behavior
Feature datasets
Geometric networks
Feature classes
Relationship classes
Fields
Subtypes
Elements
Domains
Connectivity rules
Relationship rules
Custom features
Feature class extensions
Custom interfaces

This appendix provides a review of the modeling of custom behavior geodatabase elements using UML and CASE tools, in particular the generation of custom COM classes. An overview of the general modelling process and a discussion of the modeling concepts used are also given for context. You can find more information about modeling structural and parameterized behavior elements in the ESRI book Building a Geodatabase.

Overview of using the ESRI CASE Tools

The ESRI CASE tools help you to create COM classes that implement the behavior of custom features and database schemas in which the custom feature properties are maintained.

The basic procedure to use the CASE tools is summarized below.

First, create a UML object model of your geodatabase structure. The model should be based on one of the templates provided by ESRI as part of ArcGIS. The templates are available for Microsoft Visio or Rational Software Corporation's Rational Rose and can be found in the CASE Tools subdirectory of your ArcGIS installation. The templates contain a UML representation of the portion of the ArcGIS object model necessary to model a geodatabase.

After you have created and checked your model, you need to export it to the Microsoft Repository or to an XML Metadata Interchange (XMI) file. The intermediate format you choose depends on your modeling software. XMI is a more recent technology than the Repository.

At this point, you can use the ESRI Semantics Checker to verify the validity of the model. This tool verifies that the geodatabase elements in a model are correctly specified. The Semantics Checker is available from the template diagram in Visio, and can also be run within Rational Rose using scripting; it can validate exported data either in XMI format or in the Repository. For more information about the semantics checker, see the ESRI book Building a Geodatabase.

You can then use the exported model in the ESRI CASE tools for code and schema generation. These tools can use either XMI or Repository format.

You can generate code to implement custom behavior by using the ESRI Code Generation Wizard add-in for Visual Studio. By running the wizard, you can create a C++, ATL-based project with stub classes based on the objects defined in the UML model. You can then add custom behavior to these classes and compile the project into a DLL. The DLL acts as a carrier for the custom feature and class extension COM classes.

Finally you can create a geodatabase schema for your model using the ESRI Schema Wizard in ArcCatalog. This wizard associates your custom features and class extensions with the feature classes created in the schema. Again, you can find more information about creating schemas in Building a Geodatabase.


The ESRI Semantics Checker can be used to check the validity of an exported UML model.
The ESRI Code Generation Wizard can be used to produce stub code for custom geodatabase classes.
The ESRI Schema Wizard, a command available in ArcCatalog, can be used to create a geodatabase schema based on a UML object model.


Creating UML object models for custom classes

The ESRI Template model

You can create new UML object models from the ESRI template diagrams. The diagrams contain information about the geodatabase data access objects, specifically classes and interfaces relevant to the creation of custom features and class extensions.

The template diagrams have a hierarchical structure based on UML packages. A given model has, at the minimum, four packages. ESRI Interfaces, ESRI Classes, Workspace, and Logical View (a logical root which contains the other three packages). Interfaces of the geodatabase API are defined under the ESRI interfaces package, for example IRowEvents. Likewise, COM classes of the geodatabase API are defined under ESRI Classes, for example ClassExtension. The workspace package represents a geodatabase. Under it, you can create common geodatabase elements, such as domains, feature datasets, and tables.

The UML Navigator window in Visio is used to explore the UML classes in the ESRI template. The template contains classes representing geodatabase data access objects. The UML Navigator also helps you create your own UML model containing classes based on the ESRI classes.

Modeling Concepts

To help understand the concepts involved in modeling custom behavior, look at the extract of an electric utilities UML object model. The model represents a transformer custom feature (Transformer) and its associated class extension (TransformerClassExtension).

Custom Features

Transformer is derived from the ESRI class SimpleJunctionFeature. This means a transformer will provide exactly the same services as a simple junction feature. In other words, it will implement the same interfaces its parent implements (type inheritance). In total, the transformer must implement approximately 20 system-defined interfaces, such as IRow, IFeatureDraw, and ISimpleJunctionFeature. Clients of such interfaces include ArcMap, ArcCatalog, and the geodatabase itself.

Custom features are modelled in UML by creating a class derived from one of the feature classes in the ArcInfo UML model.

Custom features are COM classes that implement interfaces. This relationship is modeled in UML with a dependency stereotyped as 'refines'. In the sample model, Transformer implements ITransformer, a developer-defined interface. An interface is modeled as a UML class marked with the stereotype 'interface'. Interfaces are abstract classes because they do not have code implementing them. In a way, they are a specification of the services the implementing class must provide. Through these interfaces, custom features provide services on a specific domain, in this case, electrical utilities. Applications developed on top of ArcGIS are the clients of these services.

Class extensions

Class extensions are created by type-inheriting either from ObjectClassExtension or FeatureClassExtension. In UML, they are required to follow a naming convention—the name of the class followed by "ClassExtension" (TransformerClassExtension, for example).

Class extensions do not have fields but may implement developer-defined or optional ESRI geodatabase interfaces such as IObjectClassValidation. Optional class extension interfaces are available under the ESRI interfaces package in the UML templates.

You will find all the optional class extension interfaces under the ESRI Interfaces package in the UML Navigator.

Schema creation with custom features and class extensions

When you use the ESRI Schema Creation Wizard, a feature in the UML object model will create a feature class in the target geodatabase. For example, when the schema is created for the electric utilities model, Transformer will become a feature class and its attributes will become fields (a Field named MainPeriodicity will contain integer values). Notice the types of the fields are taken from the esriFieldType enumeration, while the types in the interfaces are C++ automation types.

During schema creation, if custom code was generated, you have the opportunity to assign the custom feature and its class extension to the newly created feature class. For example, the Transformer class can be selected as the Behavior class for the new feature class in the Behavior tab of the Properties dialog box for the feature class. The class extension can also be specified here.

In the ESRI Schema Wizard you can specify that a feature class contains custom features and also associate any class extensions.

The lists of available custom features and class extensions shown in the wizard are filled based on those registered in the system; therefore, the DLL should be registered before running the wizard.

The generation of code to create custom features and class extensions is an optional step when using CASE tools. If custom classes are not required by the model, the Schema Wizard will, by default, associate the appropriate ESRI COM class with each created feature class.

Note that the Schema Wizard creates an instance of every custom feature or class extension registered in the system and queries them for some information, for example, their feature type. To avoid crashes, custom features and class extensions should handle error conditions properly during construction.


Generating code

ESRI Code Generation Wizard

The ESRI Code Generation Wizard works inside Visual Studio and can be used to generate an ATL-based C++ project with stub code for the custom features and class extensions in your UML model.

To load the Code Generation Wizard, follow these steps:

  1. In Visual Studio, click Tools and click Customize.
  2. Click the Add-ins and Macro Files tab.
  3. Click Browse to search for the add-in. Click the Files of type dropdown list and choose Add-ins (.dll). Browse to your ArcGIS installation directory, find the Bin subdirectory, and choose CodeGenWiz.dll. Click Open to add the add-in to the list.
  4. Choose the ESRI Code Generation Wizard in the add-ins list, then close the Customize dialog box. The wizard is now available on a toolbar in Visual Studio.

The ESRI Code Generation Wizard can be run from inside Visual Studio.

Using the code wizard

Close any open workspaces in Visual Studio, then run the ESRI Code Generation Wizard. The wizard will first ask you to select the repository where your model is stored.

The wizard will display the hierarchy of objects in your model. At this point, you can define implementation reuse options for each object in your model. For example, to generate a custom feature class for Transformer, ensure the check box next to Transformer is selected.

It is not necessary to generate code for all the UML classes in a model. The model shown includes a class called Cable, a generalization of SimpleEdgeFeature. In this case, Cable can be adequately represented by a SimpleEdgeFeature, as it does not implement any custom interfaces or need to override any implementation of the existing SimpleEdgeFeature. Therefore, you would not select this class for code generation in the wizard.

It is not necessary to generate code for all the UML classes in a model. In this case, Cable is not selected for code generation, but Transformer is.

Code reuse by aggregation or containment

A custom feature is required to implement a number of system-defined interfaces so that ArcGIS can use it successfully. Implementing all the interfaces locally could prove to be a difficult task. COM aggregation and containment are simple techniques you can employ to reuse the implementation already present in ArcGIS COM classes.

Aggregation and containment are techniques you can use to make use of the implementation already present in ArcGIS geodatabase classes.

In both cases, the object to reuse is placed inside the object reusing the implementation. Each interface implemented by the inner object can be directly exposed (COM aggregation) or indirectly exposed (COM containment). See the discussion on COM aggregation and containment in Introduction to COM.

When developing custom features, COM containment should be used when the custom feature changes or adds behavior to the implementation provided by the inner object. For example, in the electric utilities example, it is decided to contain IRowEvents in Transformer so that a transformer may respond to the events of that interface.

However, a custom feature may if required aggregate all the interfaces implemented by its inner object and only provide custom behavior through developer-defined interfaces (ITransformer in this example).

For each custom feature, the Code Generation Wizard will allow you to select what interfaces should be contained or aggregated.

Class Descriptions

In the Code Generation Wizard you can optionally choose to create a class description COM class for each custom feature in the model. Such COM classes describe the custom feature itself, so a feature class can be created using ArcCatalog without using the Schema Wizard.

The class description class will implement the IObjectClassDescription and IFeatureClassDescription interfaces. Code for class descriptions cannot be generated if the UML model includes relationship classes, subtypes, or geometric networks; therefore, class descriptions cannot be generated for the electric utilities example.


Generated Code

The last screen of the ESRI Code Generation Wizard will prompt you to specify a new output workspace for the generated code. After choosing the output, the wizard will create a Visual Studio C++ workspace containing the following:

  1. Registration script (.rgs), header (.h), and implementation (.cpp) files for each custom feature and class extension selected in the wizard
  2. IDL with the definition of COM classes, interfaces, and type library
  3. Other standard C++/ATL files

A view of the classes created in the DLL by the electric utilities example model.

Rgs and IDL files

The registration script creates the registry keys and values in the registry for each custom feature and class extension. It also registers them under the appropriate component category.

The project's IDL contains the definition of the COM classes and interfaces created by the developer in the model. ArcGIS software's COM classes and interfaces are imported using the importlib directive, so types, such as IRowEvents, are available to the type library being created.

Header and implementation files

Attributes in interfaces yield accessor and mutator methods. For example, the Weight attribute in the ITransformer interface generates the following IDL code:

[Visual C++]
[  propget ... ] HRESULT Weight([out, retval] double* pWeight);
[  propput ... ] HRESULT Weight([in] double Weight);

UML operations yield methods in the interface. The method NextMaintenance generates the following IDL code:

[Visual C++]
HRESULT NextMaintenance([out, retval] DATE* pNextMaintenance);

Read-only and write-only properties are created using methods prefixed with get_, put_, and propput_, as shown in the following table.

Prefix / Sample IDL
get_Foo : double [ propget ] HRESULT Foo ([out, retval] double * pFoo);
put_Foo (Y : double) [ propput ] HRESULT Foo ([in] double Y);
putref_Foo (Y : IY) [ propputref ] HRESULT Foo ([in] IY * pIY);

Each time a custom feature is created, an instance of the inner ArcGIS COM class needs to be created as well. To achieve this, the code wizard also adds stub code to the FinalConstruct of custom features (ATL calls FinalConstruct as soon as the C++ class has been instantiated).

In the electric utility example, the C++ code generated for Transformer includes the creation of the inner SimpleJunctionFeature in its FinalConstruct.

[Visual C++]
HRESULT Transformer::FinalConstruct()
{
  // Creates instance of inner object
  IUnknown * pOuter = GetControllingUnknown();
  if (FAILED (CoCreateInstance(__uuidof(SimpleJunctionFeature),
      pOuter,
      CLSCTX_INPROC_SERVER,
      IID_IUnknown,
      (void**) &m_pInnerUnk)))
  return E_FAIL;

In the same function, a QI is made for each COM-contained interface. A member variable will hold a reference to the interface implemented by the inner object. For the Transformer, this affects the IRowEvents interface.

[Visual C++]
  // QI for IRowEvents
  if (FAILED(m_pInnerUnk->QueryInterface(IID_IRowEvents,
    (void**)&m_pIRowEvents)))
    return E_FAIL;
  pOuter->Release();
  return S_OK;
}

The header generated for the transformer declares the ATL COM MAP. These macros are used to specify which interfaces are implemented locally and which are aggregated.

In the example, ITransformer and IRowEvents are implemented locally, and all other interfaces implemented by the inner object are aggregated.

BEGIN_COM_MAP(Transformer)
  COM_INTERFACE_ENTRY(ITransformer)
  COM_INTERFACE_ENTRY(IRowEvents)
  COM_INTERFACE_ENTRY_AGGREGATE_BLIND(m_pInnerUnk)
END_COM_MAP()

Stub code is also generated for the interfaces defined in the model, which by default returns E_NOTIMPL for each method. It is your responsibility to add implementation code to these methods. In the code generated from electric utilities model, the ITransformer interface in the transformer C++ class looks like the code below.

[Visual C++]
STDMETHODIMP Transformer::get_Weight(double* pWeight)
{
  return E_NOTIMPL;
}
  
STDMETHODIMP Transformer::put_Weight(double Weight)
{
  return E_NOTIMPL;
}
  
STDMETHODIMP Transformer::NextMaintenance(DATE* pNextMaintenance)
{
  return E_NOTIMPL;
}

When coding the custom feature, you may add or change the implementation of a contained interface provided by the inner object. For each method in the interface, you can choose to forward the call to the inner feature or use your own implementation. The former option is used by the wizard by default.

For the electric utilities example, code is generated for the IRowEvents interface inside the transformer C++ class, allowing you to write your own implementation for each method in the interface (recall that pointers to contained interfaces are acquired in the FinalConstruct).

[Visual C++]
STDMETHODIMP Transformer::OnChanged()
{
  return m_pIRowEvents->OnChanged();
}
  
STDMETHODIMP Transformer::OnDelete()
{
  return m_pIRowEvents->OnDelete();
}...

Back to top

See also TreeFeature Custom Feature Example.