Establishing a Connection

FDO API

 
Establishing a Connection
 
 
 

As mentioned in a previous section, Connection Semantics, the FDO API uses a provider to connect to a data store and its underlying data source technology. These data source technologies must be installed and configured. Certain values generated during data source installation and configuration are used as arguments during the connection process. Because the FDO API does not provide any methods to automate the collection and presentation of these configuration values, either the application developer must request the user to input these configuration values during the connection process, or the application developer can provide an application configuration interface, which would populate the application with the container configuration values and thus allow the user to choose them from lists.

NoteFor more information about connecting, see The Essential FDO.

A connection can be made in either one or two steps:

  • One-step connection. If the user sets the required connection properties and calls the connection object’s Open() method once, the returned state is FdoConnectionState_Open, no additional information is needed.
  • Two-step connection. If the user sets the required connection properties and calls the connection object’s Open() method, the returned state is FdoConnectionState_Pending, additional information is needed to complete the connection. In this case, the first call to Open() has resulted in the retrieval of a list of values for a property that becomes a required property for the second call to the Open() method. After the user has selected one of the values in the list, the second call to Open() should result in FdoConnectionState_Open.

Connecting to a data store by way of the MySQL or the ArcSDE provider, for example, can be done in either one or two steps. In the first step, the data store parameter is not required. If the user does not give the data store parameter a value, the FDO will retrieve the list of data store values from the data source so that the user can choose from them during the second step. Otherwise the user can give the data store a value in the first step, and assuming that the value is valid, the connection will be completed in one step.

For the purpose of this example, let’s assume that the user has installed MySQL on his local machine. During the installation he was prompted to assign a password to the system administrator account whose name is ‘root’. He set the password to ‘test’.

The following steps are preliminary to establishing a connection:

  1. Get the list of providers.
    FdoPtr<FdoProviderRegistry> registry = (FdoProviderRegistry *)FdoFeatureAccessManager::GetProviderRegistry();
    FdoProviderCollection * providers = registry->GetProviders();
  2. Get the display names for all of the providers in the registry. An example of a display name might be OSGeo FDO Provider for MySQL.
    FdoStringP displayName;
    FdoStringP internalName;
    FdoPtr<FdoProvider> provider;
    int count = providers->GetCount();
    for(int i = 0; i < count; i++) {
      provider = providers->GetItem(i);
      internalName = provider->GetName();
      displayName = provider->GetDisplayName();
      // add displayName to your list
    }
  3. Use the display names to create a menu list, from which the user will select from when making a connection.

After the user initiates a provider display name from the connection menu, do the following:

  1. Loop through the providers in the registry until you match the display name selected by the user from the connection menu with a provider display name in the registry and retrieve the internal name for that provider. An example of an internal could be OSGeo.MySQL.3.2.
    FdoStringP internalName = provider->GetName();
  2. Get an instance of the connection manager.
    FdoPtr<FdoConnectionManager> connectMgr = (FdoConnectionManager *)FdoFeatureAccessManager::GetConnectionManager();
  3. Call the manager’s CreateConnection() method using the provider internal name as an argument to obtain a connection object.
    FdoPtr<FdoIConnection> fdoConnection = connectMgr->CreateConnection(L”OsGeo.MySQL.3.2”);
  4. Obtain a connection info object by calling the connection object’s GetConnectionInfo() method.
    FdoPtr<FdoIConnectionInfo> info = fdoConnection->GetConnectionInfo();
  5. Obtain a connection property dictionary object by calling the connection info object’s GetConnection Properties() method and use this dictionary to construct a dialog box requesting connection information from the user.
    FdoPtr<FdoIConnectionPropertyDictionary> ConnDict = info->GetConnectionProperties();
  6. Get a list of connection property names from the dictionary and use this list to get information about the property. The following code loops through the dictionary getting all of the possible information.
    NoteAn attempt to get the values of an enumerable property is made only if the property is required.
    FdoInt32 count = 0;
    FdoString ** names = NULL;
    FdoStringP name;
    FdoStringP localname;
    FdoStringP val;
    FdoStringP defaultVal;
    bool isRequired = false;
    bool isProtected = false;
    bool isFilename = false;
    bool isFilepath = false;
    bool isDatastorename = false;
    bool isEnumerable = false;
    FdoInt32 enumCount = 0;
    FdoString ** enumNames = NULL;
    FdoStringP enumName;
    names = ConnDict->GetPropertyNames(count);
    for(int i = 0; i < count; i++) {
      name = names[i];
      val = dict->GetProperty(name);
      defaultVal = dict->GetPropertyDefault(name);
      localname = dict->GetLocalizedName(name);
      isRequired = dict->IsPropertyRequired(name);
      isProtected = dict->IsPropertyProtected(name);
      isFilename = dict->IsPropertyFileName(name);
      isFilepath = dict->IsPropertyFilePath(name);
      isDatastorename = dict->IsPropertyDatastoreName(name);
      isEnumerable = dict->IsPropertyEnumerable(name);
      if (isEnumerable) {
        if (isRequired) {
          enumNames = dict->EnumeratePropertyValues(name, enumCount);
          for(int j = 0; j < enumCount; j++) {
            enumName = enumNames[j];
          }
        }
      }
    }
  7. Use the GetLocalizedName method to obtain the name of the property to present to the user. Calls to dictionary methods need the value of the internal name in the string array returned by GetPropertyNames(). So when the user selects the localized name in the menu, the program must map the localized name to the internal name.
  8. Use the IsPropertyRequired method to determine whether to mark the line as either required or optional; the dialog box handler should not permit the user to click OK in the dialog box unless a required field has a value.
  9. Use the IsPropertyProtected method to determine whether the dialog box handler should process the field value as protected data, for example, a password.
  10. Use the IsPropertyEnumerable and IsRequired methods to determine whether to call the EnumeratePropertyValues method to get a list of valid values.
    NoteCall the EnumeratePropertyValues method only if both methods return true. Otherwise be prepared to catch an exception if there is no pending connection. The assumption is that a connection exists and the program is retrieving values from the data store.

As shown in the code lines above, the EnumeratePropertyValues method takes a property name and an updates integer argument and returns a string array. The updates integer will say how many values are in the returned array. Present the list of choices to the user.

If the property is not enumerable, present the values returned by either the GetProperty or GetPropertyDefault methods to the user.

Now that the user has seen the set of properties in the dictionary, s/he can set the required properties. A property is set by calling the dictionary’s SetProperty method. The MySQL connection property names are Username, Password, Service, and DataStore. The dictionary tells us that Username, Password, and Service are required properties and that DataStore is not required. Let’s connect to the MySQL as root.

ConnDict->SetProperty(L”Username”, L”root”);
ConnDict->SetProperty(L”Password”, L”test”);
ConnDict->SetProperty(L”Service”, L”localhost”);
Notefdoconnection->GetConnectionString() returns Username=root;Password=test;Service=localhost;. fdoconnection->SetConnectionString(L”Username=root;Password=test;Service=localhost;”); would set the connection properties to the same values as the three calls above to the connection dictionary’s SetProperty() method.

Open the connection.

FdoConnectionState state = fdoConnection->Open();

The value of state is FdoConnectionState_Pending. An examination of the connection dictionary will reveal that the DataStore property is now required.

When the user checks the command capabilities, he discovers that he can create a data store.

FdoPtr<FdoICommandCapabilities> commandCapabilities = fdoConnection->GetCommandCapabilities();
bool bSupportsCreateDatastore = false;
FdoInt32 numCommands;
FdoIn32 * commands = commandCapabilities->GetCommands(numCommands);
for(int i = 0; i < numCommands; i++) {
  switch(commands[i]) {
    case FdoCommandType_CreateDataStore : bSupportsCreateDatastore = true;
  }
}

He can use the pending connection to MySQL to create the datastore. Use the connection object to create the FdoICreateDataStore command object. Use the command object to create the FdoIDataStorePropertyDictionary object and find out from this object what properties you must define. Use the dictionary object to set the required properties and then execute the command to create the ‘fdo_user’ data store. The only required property is DataStore.

NoteThe FdoIDataPropertyDictionary and the FdoIConnectionPropertyDictionary classes are both derived from FdoIPropertyDictionary. The code used above to access the FdoIConnectionPropertyDictionary object works for the FdoIDataPropertyDictionary.
FdoPtr<FdoICreateDataStore> createDataStoreCmd = dynamic_cast<FdoICreateDataStore *> (fdoConnection->CreateCommand(FdoCommandType_CreateDataStore));
FdoPtr<FdoIDataStorePropertyDictionary> createDsDict = createDataStoreCmd->GetDataStoreProperties();
createDsDict->SetProperty(L”DataStore”, L”fdo_user”);
createDataStoreCmd->Execute();

Now use the connection property dictionary to set the DataStore property to ‘fdo_user’ and call the Open() method on the connection object. This method should return FdoConnectionState_Open.