= FDO RFC 20 - Enhanced Capabilities Support = This page contains an change request (RFC) for the FDO Open Source project. More FDO RFCs can be found on the [wiki:FDORfcs RFCs] page. == Status == ||RFC Template Version||(1.0)|| ||Submission Date|| April 30, 2008 || ||Last Modified|| Thomas Knoell [[Timestamp]]|| ||Author||Thomas Knoell|| ||RFC Status||Deferred|| ||Implementation Status||Pending|| ||Proposed Milestone||3.4.0.0|| ||Assigned PSC guide(s)||Greg Boone|| ||'''Voting History'''||(vote date)|| ||+1|| || ||+0|| || ||-0|| || ||-1|| || == Motivation == The objective is to simplify the current FDO capability API interface set in that the addition of a new capability does not require FDO, providers (if they don't immediately support the new capability) and applications (if they don't use the new capability) to be rebuild. == Proposals == Currently, there is a FDO interface for each capability FDO supports. Any change to the capability set requires a new interface to be added to FDO to retrieve the value. As a result, FDO is no longer binary compatible once this is done and requires a re-build of FDO and any provider wanting to use the updated FDO version. The aim of this requirement is to address this issue. The idea is to have a set of simplified capability interfaces that allows the addition of a new capability without requiring to rebuild FDO, any provider that does not immediately support the new capability or any application if the capability is not used. Doing this would not only reduce the number of capability interfaces but also the number of capability classes in FDO. Obviously, the new interfaces must be able to replace the current ones. Looking at the existing capability interfaces, they can be categorized as outlined next: * Boolean: These functions return a flag indicating whether or not a capability is supported. The category includes routines such as ''!SupportsLocking()'', ''!SupportsCompositeId()'' or ''!SupportsAutoIdGeneration()''. * Enumerates: These functions return an identifier from an enumeration. The category includes routines such as ''!GetThreadCapability()''. * Array of enumerated values: These functions return an array of values from an enumeration and the number of elements in that array. The category includes routines such as ''!GetSpatialContextTypes()'' or ''!GetLockTypes()''. * Collection: These functions return a collection of complex objects. The category includes routines such as ''!GetFunctions()''. * Bit-mask values: These functions return a bit-mask value of enumerated values. The category includes routines such as ''!GetDimensionality()''. * Capability based numbers: These functions take a capability identifier and return the corresponding capability value. The category includes routines such as ''!GetMaximumDataValueLength()'' or ''!GetNameSizeLimit()''. * Numbers: These functions return number values of different types. The category includes func-tions such as ''!GetMaximumDecimalPrecision()'' or ''!GetMaximumDecimalScale()''. * Strings: These functions return strings. The category includes functions such as ''!GetReservedCharactersForName()''. A capability interface class may have any number of functions of those different categories with the Boolean category containing the most functions. The simplification of the FDO capability interfaces focuses on those categories as it creates interfaces depending on the expected return type. As a result, a capability interface will be processing a number of capabilities that have the same return type and hence requires the caller to identify the capability for which the value should be returned. In addition, the functions must also be able to indicate to the caller if a provided capability identifier is unknown. Therefore, the signature definition of those new interfaces must have at least two parameters: * A parameter to indicate the capability for which the value is to be retrieved. * A parameter with which the interface can indicate to the caller that the provided capability identifier is unknown. Depending on the category, there may be the need for additional parameters – for example, the function returning an array of enumerated values also has to return the number of entries in that array. The new capability interfaces will be defined in a new class - ''!FdoICapability'' - that resides in the directory Fdo\Unmanaged\Inc\Fdo\Connections\Capabilities. The following outlines the class definition: {{{ #include class FdoICapability : public FdoIDisposable { public: FDO_API virtual bool GetBooleanCapability (FdoInt32 capability, bool *isUnknown) = 0; FDO_API virtual bool GetBooleanCapability (FdoInt32 capability, FdoString *value, bool *isUnknown) = 0; FDO_API virtual FdoInt32 GetInt32Capability (FdoInt32 capability, bool *isUnknown) = 0; FDO_API virtual FdoInt64 GetInt64Capability (FdoInt32 capability, bool *isUnknown) = 0; FDO_API virtual FdoString *GetStringCapability (FdoInt32 capability, bool *isUnknown) = 0; FDO_API virtual FdoInt32 *GetArrayCapability (FdoInt32 capability, FdoInt32 &length, bool *isUnknown) = 0; FDO_API virtual void *GetObjectCapability (FdoInt32 capability, bool *isUnknown) = 0; } // FdoICapability }}} With the introduction of the class ''FdoICapability'', all other capability classes – ''FdoICommand'', ''FdoIConnection'', ''FdoIExpression'', ''FdoIFilter'', ''FdoIGeometry'', ''FdoIRaster'', ''FdoISchema'', ''FdoITopology'' – including their interfaces become obsolete. With the exception of the class ''FdoITopology'', there is no immediate plan to depricate those classes and functions but the intend is to do it eventually. Therefore, any application that uses the FDO capability interfaces should use the new interfaces once they become available to minimize later code changes. As mentioned, the exception is the class ''FdoITopology''. The reason why this class will be depricated immediately is the fact that FDO does not support topology and therefore the presence of topology capability is inconsistent. The proposed change deletes the class ''FdoITopology'' and its counterpart in the managed code base as well as any reference to those classes in FDO code. The addition of the class ''!FdoICapability'' as a replacement of all other FDO capability classes requires a change to the class ''!FdoIConnection'' that provides access to the capabilities. That class needs a new interface to get the capabilities: {{{ FDO_API virtual FdoICapability *GetCapability() = 0; }}} A corresponding change will also be made in the FDO managed code base: {{{ ... BEGIN_NAMESPACE_OSGEO_FDO_CONNECTIONS_CAPABILITIES ... public __gc __interface ICapability; ... END_NAMESPACE_OSGEO_FDO_CONNECTIONS_CAPABILITIES ... NAMESPACE_OSGEO_FDO_CONNECTIONS_CAPABILITIES::ICapability *GetCapability(); ... }}} The class ''FdoICapability'' has generalized interfaces for all return type categories the current set of capability interfaces return. It is feasable to add capability interfaces for all data types that FDO supports in preparation for additional capabilities that may be added at a later stage using those data types. However, the ones currently listed should cover most, if not all of the cases and hence the addition of interfaces for different FDO types is not planned. The simplification of the capability interfaces also affects code using it. This is especially the case for the new interfaces that return an array of enumerated values or a collection. Because of the generalization, the interfaces have to return a neutral rather than a specific data type as it is the case with the original interfaces. This requires the caller to cast the returned object to the expected type. The following shows an example of the old and new style request for a capability that returns an array of enumerated values. {{{ Old Style Call FdoPtr schemaCapabilities = connection->GetSchemaCapabilities(); FdoInt32 listCount; FdoDataType *supportedDataTyes = schemaCapabilities->GetSupportedAutoGeneratedTypes(listCount); New Style Call FdoPtr capability = connection->GetCapability(); bool isUnknown = false; FdoInt32 listCount = 0; FdoDataType *supportedDataTyes = (FdoDataType *)capability->GetArrayCapability( FdoCapabilityType_DataTypes, listCount, &isUnknown); }}} The change to the unmanaged code requires a corresponding change to the managed code. The class ''ICapability'' will be added at Fdo\Managed\Src\OSGeo\FDO\Connections\Capabilities (file mgICapability.h). The following outlines this new class: {{{ public __gc __interface ICapability : public System::IDisposable { public: System::Boolean GetBooleanCapability (System::Int32 capability, System::Boolean *isUnknown); System::Boolean GetBooleanCapability (System::Int32 capability, System::String *value, System::Boolean *isUnknown); System::Int32 GetInt32Capability (System::Int32 capability, System::Boolean *isUnknown); System::Int64 GetInt64Capability (System::Int32 capability, System::Boolean *isUnknown); System::String *GetStringCapability (System::Int32 capability, System::Boolean *isUnknown); System::Int32[] GetArrayCapability (System::Int32 capability, System::Boolean *isUnknown); System::Object GetObjectCapability (System::Int32 capability, System::Boolean *isUnknown); } }}} As part of the proposed change to the FDO capability interface set, a new enumeration will be added. This new enumeration - ''!FdoCapabilityType'' - contains a list of all currently supported capabilities (including the one proposed in RFC 24). The following outlines this enumeration: {{{ enum FdoCapabilityType { // Command Capabilities FdoCapabilityType_CommandList, FdoCapabilityType_SupportsParameters, FdoCapabilityType_SupportsTimeout, FdoCapabilityType_SupportsSelectExpressions, FdoCapabilityType_SupportsSelectFunctions, FdoCapabilityType_SupportsSelectDistinct, FdoCapabilityType_SupportsSelectOrdering, FdoCapabilityType_SupportsSelectGrouping, // Connection Capabilities FdoCapabilityType_ThreadCapability, FdoCapabilityType_SpatialContextTypes, FdoCapabilityType_LockTypes, FdoCapabilityType_SupportsLocking, FdoCapabilityType_SupportsTimeout, FdoCapabilityType_SupportsTransactions, FdoCapabilityType_SupportsLongTransactions, FdoCapabilityType_SupportsSQL, FdoCapabilityType_SupportsConfiguration, FdoCapabilityType_SupportsMultipleSpatialContexts, FdoCapabilityType_SupportsCSysWKTFromCSysName, FdoCapabilityType_SupportsWrite, FdoCapabilityType_SupportsMultiUserWrite, FdoCapabilityType_SupportsFlush, // Expression Capabilities FdoCapabilityType_ExpressionTypes, // Filter Capabilities FdoCapabilityType_ConditionTypes, FdoCapabilityType_SpatialOperations, FdoCapabilityType_DistanceOperations, FdoCapabilityType_SupportsGeodesicDistance, FdoCapabilityType_SupportsNonLiteralGeometricOperations, // Geometry Capabilities FdoCapabilityType_GeometryTypes, FdoCapabilityType_GeometryComponentTypes, FdoCapabilityType_Dimensionalities, FdoCapabilityTYpe_CSSupportsArcs, // Raster Capabilities FdoCapabilityType_SupportsRaster, FdoCapabilityType_SupportsStitching, FdoCapabilityType_SupportsSubsampling, FdoCapabilityType_SupportsDataModel, // Schema Capabilities FdoCapabilityType_ClassTypes, FdoCapabilityType_DataTypes, FdoCapabilityType_SupportedAutoGeneratedTypes, FdoCapabilityType_SupportedIdentityPropertyTypes, FdoCapabilityType_MaximumDataValueLength_String, FdoCapabilityType_MaximumDataValueLength_BLOB, FdoCapabilityType_MaximumDataValueLength_CLOB, FdoCapabilityType_MaximumDataValueLength_Decimal, FdoCapabilityType_MaximumDataValueLength_Boolean, FdoCapabilityType_MaximumDataValueLength_Byte, FdoCapabilityType_MaximumDataValueLength_DateTime, FdoCapabilityType_MaximumDataValueLength_Double, FdoCapabilityType_MaximumDataValueLength_Int16, FdoCapabilityType_MaximumDataValueLength_Int32, FdoCapabilityType_MaximumDataValueLength_Int64, FdoCapabilityType_MaximumDataValueLength_Single, FdoCapabilityType_MaximumDecimalPrecision, FdoCapabilityType_MaximumDecimalScale, FdoCapabilityType_NameSizeLimit_Datastore, FdoCapabilityType_NameSizeLimit_Schema, FdoCapabilityType_NameSizeLimit_Class, FdoCapabilityType_NameSizeLimit_Property, FdoCapabilityType_NameSizeLimit_Description, FdoCapabilityType_ReservedCharactersForName, FdoCapabilityType_SupportsAssociationProperties, FdoCapabilityType_SupportsAutoIdGeneration, FdoCapabilityType_SupportsCalculatedProperties, FdoCapabilityType_SupportsCompositeId, FdoCapabilityType_SupportsCompositeUniqueValueConstraints, FdoCapabilityType_SupportsDataStoreScopeUniqueIdGeneration, FdoCapabilityType_SupportsDefaultValue, FdoCapabilityType_SupportsExclusiveValueRangeConstraints, FdoCapabilityType_SupportsInclusiveValueRangeConstraints, FdoCapabilityType_SupportsInheritance, FdoCapabilityType_SupportsMultipleSchemas, FdoCapabilityType_SupportsNetworkModel, FdoCapabilityType_SupportsNullValueConstraints, FdoCapabilityType_SupportsObjectProperties, FdoCapabilityType_SupportsSchemaModification, FdoCapabilityType_SupportsSchemaOverrides, FdoCapabilityType_SupportsUniqueValueConstraints, FdoCapabilityType_SupportsValueConstraintsList, FdoCapabilityType_SupportsWritableIdentityProperties, } // enum FdoCapabilityType }}} The new enumeration will reside in the directory Fdo\Unmanaged\Inc\Fdo\Connections\Capabilities. A corresponding definition - ''!CapabilityType'' - will be added to the managed code (Fdo\Managed\Src\OSGeo\FDO\Connections\Capabilities): {{{ public __value enum CapabilityType { // Command Capabilities CapabilityType_CommandList, CapabilityType_SupportsParameters, CapabilityType_SupportsTimeout, CapabilityType_SupportsSelectExpressions, CapabilityType_SupportsSelectFunctions, CapabilityType_SupportsSelectDistinct, CapabilityType_SupportsSelectOrdering, CapabilityType_SupportsSelectGrouping, // Connection Capabilities CapabilityType_ThreadCapability, CapabilityType_SpatialContextTypes, CapabilityType_LockTypes, CapabilityType_SupportsLocking, CapabilityType_SupportsTimeout, CapabilityType_SupportsTransactions, CapabilityType_SupportsLongTransactions, CapabilityType_SupportsSQL, CapabilityType_SupportsConfiguration, CapabilityType_SupportsMultipleSpatialContexts, CapabilityType_SupportsCSysWKTFromCSysName, CapabilityType_SupportsWrite, CapabilityType_SupportsMultiUserWrite, CapabilityType_SupportsFlush, // Expression Capabilities CapabilityType_ExpressionTypes, // Filter Capabilities CapabilityType_ConditionTypes, CapabilityType_SpatialOperations, CapabilityType_DistanceOperations, CapabilityType_SupportsGeodesicDistance, CapabilityType_SupportsNonLiteralGeometricOperations, // Geometry Capabilities CapabilityType_GeometryTypes, CapabilityType_GeometryComponentTypes, CapabilityType_Dimensionalities, CapabilityTYpe_CSSupportsArcs, // Raster Capabilities CapabilityType_SupportsRaster, CapabilityType_SupportsStitching, CapabilityType_SupportsSubsampling, CapabilityType_SupportsDataModel, // Schema Capabilities CapabilityType_ClassTypes, CapabilityType_DataTypes, CapabilityType_SupportedAutoGeneratedTypes, CapabilityType_SupportedIdentityPropertyTypes, CapabilityType_MaximumDataValueLength_String, CapabilityType_MaximumDataValueLength_BLOB, CapabilityType_MaximumDataValueLength_CLOB, CapabilityType_MaximumDataValueLength_Decimal, CapabilityType_MaximumDataValueLength_Boolean, CapabilityType_MaximumDataValueLength_Byte, CapabilityType_MaximumDataValueLength_DateTime, CapabilityType_MaximumDataValueLength_Double, CapabilityType_MaximumDataValueLength_Int16, CapabilityType_MaximumDataValueLength_Int32, CapabilityType_MaximumDataValueLength_Int64, CapabilityType_MaximumDataValueLength_Single, CapabilityType_MaximumDecimalPrecision, CapabilityType_MaximumDecimalScale, CapabilityType_NameSizeLimit_Datastore, CapabilityType_NameSizeLimit_Schema, CapabilityType_NameSizeLimit_Class, CapabilityType_NameSizeLimit_Property, CapabilityType_NameSizeLimit_Description, CapabilityType_ReservedCharactersForName, CapabilityType_SupportsAssociationProperties, CapabilityType_SupportsAutoIdGeneration, CapabilityType_SupportsCalculatedProperties, CapabilityType_SupportsCompositeId, CapabilityType_SupportsCompositeUniqueValueConstraints, CapabilityType_SupportsDataStoreScopeUniqueIdGeneration, CapabilityType_SupportsDefaultValue, CapabilityType_SupportsExclusiveValueRangeConstraints, CapabilityType_SupportsInclusiveValueRangeConstraints, CapabilityType_SupportsInheritance, CapabilityType_SupportsMultipleGeometries, CapabilityType_SupportsMultipleSchemas, CapabilityType_SupportsNetworkModel, CapabilityType_SupportsNullValueConstraints, CapabilityType_SupportsObjectProperties, CapabilityType_SupportsSchemaModification, CapabilityType_SupportsSchemaOverrides, CapabilityType_SupportsUniqueValueConstraints, CapabilityType_SupportsValueConstraintsList, CapabilityType_SupportsWritableIdentityProperties, } // CapabilityType }}} Like the command enumeration, the capability enumeration can be extended by the providers to add their own capabilities if this is required. ==== Issues ==== The introduction of the simplified FDO capability interfaces will result in some usability issues not present in the current implementation because it uses different functions for each of the supported capabilities. This means that the user does not have to know much about the capability he/she is about to use. Instead, the user gets hold of the capability class, finds the corresponding interface and executes it. By doing so, the user is also ensured that a valid value is returned that can be used for further processing in an application. With the simplified version of the FDO capability interfaces, this is no longer the case. Because a given interface now serves many capabilities, the user requires some knowledge about the capability before being able to get the value and faces additional challenges as result of a capability interface call: * The user has to identify the capability for which the value is to be returned. * The user has to know the capability's return type in order to select the correct capability interface in the first place. * The user has to deal with error scenarios previously unknown as for a capability interface the provided capability identifier may be unknown. Each of the issues are addressed in more detail next. '''''Capability Identification''''' To keep the interface generic and reach the objective outlined for this enhancement, the data type for the capability identifier has to be generic as well. Two options to achieve this were discussed in this context: * The first option would define the parameter as a string. To identify the capability the user would enter the capability name. * The second option would define the parameter as a numeric type. To identify the capability the user would enter the numeric representation of the capability. Both options in common is the question how a user would know what to provide as the capability identifier. For the first option, the user would have to know a valid name, for the second the numeric representation. It would be possible to define the valid identifiers in FDO. However, because of the objective to be reached with this enhancement this definition would act merely as a kind of documentation than concrete help. For example, if a new capability is to be added, the list may not be updated as otherwise FDO would require a rebuild which would trigger additional rebuilds of providers and applications - something that is to be avoided. Therefore, the list would only represent a snapshot of available capabilities. The same would apply for the documentation of the capabilities in documents (like the User Guide) or help files. Despite this, the proposed solution adds an enumeration that contains all the capabilities FDO supports (including the ones proposed in the RFC). As indicated before it is a snapshot of the then available capability set only and by no means should it be looked at as a complete list. It provides some rudamentary support to the users to identify a capability. '''''Interface Selection''''' To select the correct FDO capability interface to retrieve the value of a capability, the user has to know the capability's return type. Like with the capability identifier, this is information that requires to be documented somewhere where the user can easily access it. The current intent is to add this information to the description of the enumerations FdoCapabilityTYpe and CapabilityType. An alternative option would have been to split the current enumeration into different enumeration depending on the return value. However, given the usability of those enumerations (see previous section) it is not seen as a necessity to do so. '''''Error Handling''''' Unlike with the current FDO capability interfaces, with the simplified version, a capability interface may have to indicate to a caller that a provided capability identifier is unknown. A common scenario may be that a new capability is added and not all providers would support it immediately. If the corresponding FDO capability interface was to be invoked with the new capability identifier for a provider that does not yet support it, the interface must be able to indicate this to the caller. As defined in the proposed solution, this aspect has been addressed by using a function parameter (isUnknown) to inform the caller whether or not the provided capability is unknown. If so, the caller has to ignore any value the function may return. Alternative options for the error handling were also discussed in this context. Those include: * Exception: The function would throw an exception if the provided capability identifier is unknown. * Predefined Default Value: Each FDO capability interface will have a predefined value being returned if the provided capability is unknown. * Custom Default Value: In this case the caller supplies the value to be returned if a provided capability identifier is unknown. Those options were dismissed for various reasons. Whereas the first option was dismissed because of cost related issues, the two other options were dismissed because it appears impossible to define a value for each of the interfaces that could be used to reliably indicate that a capability indentifier is unknown. For example, the interface handling capabilities returning a boolean value, can return either true or false, both of which indicate valid responses for a capability. Based on this, a caller receiving such a value cannot distinguish between whether this represents a valid capability value or that the capability is unknown. == Test Plan == Existing unit tests will be enhanced and new unit tests added to test all changes. == Funding/Resources == Autodesk to provide resource / funding to implement the feature for the affected providers.