wiki:FdoSchemaDeepCopy

Version 3 (modified by gregboone, 17 years ago) ( diff )

--

FDO Schema DeepCopy Support

Overview

As a result of further integrating the FDO API into the Autodesk Map and Autodesk MapGuide Enterprise product lines, an request was generated senior developers which would see the FDO community implement DeepCopy or Clone support directly into the FDO API class definitions. The lack of such support was seen as a deficiency in FDO that forced users of the API to write such functionality themselves.

The following sections outline how this new functionality will be implemented.

Definitions

The following changes will be made to the FDO API in order to support the process of deep copying or cloning FDO schema and data types.

FdoSchemaCopyContext Class

An FdoSchemaCopyContext class will be added to the FDO Schema API

FdoSchemaCopyContext is context class that will be used to assist in process of cloning schemas and their associated elements. FdoSchemaCopyContext is designed to contain a schema element map which will store instances of previously copied schema elements. Since FDO schema objects are often associated to one another, and a deep cloning process by design must copy the entire schema object, it is necessary to know if the associated objects have been previously copied. Implementing a mapping for the copied schema elements will avoid creating duplicate objects when cloning an FDO schema.

The FdoSchemaCopyContext class will have the following definition:

/// \brief
/// A Map that will allow copied schema elements to be tracked  
/// and will prevent duplicate elements from being copied.
typedef std::map <FdoSchemaElement*, FdoSchemaElement*> FdoSchemaElementMap;

/// \brief
/// A Map pair that will allow copied schema elements to identified and stored
/// in a FdoSchemaElementMap.
typedef std::pair <FdoSchemaElement*, FdoSchemaElement*> FdoSchemaElementPair;

/// \brief
/// A Map iterator that will allow iteration over a FdoSchemaElementMap.
typedef FdoSchemaElementMap::const_iterator FdoSchemaElementMapIterator;

/// \brief
/// A schema context class that is used to assist in process 
/// of cloning schema elemts. The schema element map contained 
/// by this class assists the DeepCopy process in avoiding duplicate 
/// schema element objects from being copied.
class FdoSchemaCopyContext : public FdoDisposable
{
public:
    /// \brief
    /// Creates a new instance of an FdoSchemaCopyContext
    /// 
    /// \param identifiers
    /// An optional set of identifiers that will constrain 
    /// the class indentifiers to copy. Use this collection to 
    /// copy a potion of an FDO class definition
    /// 
    /// \return
    /// Returns a new instance of FdoSchemaCopyContext
    /// 
    static FdoSchemaCopyContext* Create( FdoIdentifierCollection *identifiers = NULL );

public:
    /// \brief
    /// Gets the element map containing the copied elements 
    /// referenced by the copy context
    /// 
    /// \return
    /// Returns the element map containing the copied elements
    /// 
    const FdoSchemaElementMap * GetSchemaElementMap();

    /// \brief
    /// Inserts a source/copied pair into the element map 
    /// 
    /// \sourceElement
    /// The source element from which the element was copied
    /// 
    /// \copiedElement
    /// The copied element created from the source element
    /// 
    void InsertSchemaElement( FdoSchemaElement* sourceElement, 
                              FdoSchemaElement* copiedElement );

    /// \brief
    /// Sets the FDO identifier list that will constrain the 
    /// list of class properties to be copied
    /// 
    /// \param identifiers
    /// An optional set of identifiers that will constrain 
    /// the class indentifiers to copy. Use this collection to 
    /// copy a potion of an FDO class definition
    /// 
    void SetIdentifierConstraints( FdoIdentifierCollection* identifiers );

    /// \brief
    /// Find a copied element in the schema element 
    /// map based on it's source object
    /// 
    /// \param element 
    /// Input the element to search for in the element map
    /// 
    /// \return
    /// Returns the previously copied schema element 
    /// if found in the collection, otherwise NULL
    /// 
    template <typename T> T* FindSchemaElement( T* element )
    {
        if (m_schemaMap == NULL) {
            throw FdoException::Create(
                FdoException::NLSGetMessage(FDO_NLSID(FDO_4_UNREADY)));
        }

        T* retElem = NULL;

        FdoSchemaElementMapIterator elementIterator = m_schemaMap->find(element);
        if (elementIterator != m_schemaMap->end()) {
            retElem = dynamic_cast<T*>(elementIterator->second);
            if (retElem == NULL) {
                throw FdoException::Create(
                    FdoException::NLSGetMessage(FDO_NLSID(CLNT_3_NULLPOINTER)));
            }
        }

        return FDO_SAFE_ADDREF(retElem);
    }

protected:
    /// \brief
    /// Default Constructor
    FdoCommonSchemaCopyContext( void );

    /// \brief
    /// Destructor (Virtual)
    virtual ~FdoCommonSchemaCopyContext();

    /// \brief
    /// The Disposal method for this object. Dispose is called 
    /// when the objects RefCount == 0. Dispose will in turn 
    /// invoke the objects destructor
    virtual void Dispose();

private:
    /// \brief
    /// The std::map containing references to the copied schema elements
    FdoSchemaElementMap * m_schemaMap;

    /// \brief
    /// The identifier collection that will contrain the class properties
    /// to be copied.
    FdoPtr<FdoIdentifierCollection> m_identifierConstraints;
};

/// \brief
/// FdoSchemaCopyContextP is a FdoPtr on FdoSchemaCopyContext. Provided for convenience.
typedef FdoPtr<FdoSchemaCopyContext> FdoSchemaCopyContextP;

DeepCopy Function

The actual process of copying or cloning individual elements within an FDO schema shall be accomplished with the addition of a standard DeepCopy method that will be added to all types that derive from FdoSchemaElement. It shall be the responsibility of the DeepCopy method to copy itself and all its contained objects and data.

The following DeepCopy function will be added to the set of schema class definitions listed in the subsequent section.

    /// \brief
    /// Deep copy this instance of class Fdo[ClassName].
    /// 
    /// \param context
    /// An schema copy context which will contain previously copied elements
    /// from the schema being cloned
    /// 
    /// \return
    /// Returns a cloned instance of class Fdo[ClassName]
    /// 
    FDO_API virtual Fdo[ClassName]* DeepCopy( FdoSchemaCopyContext* context = NULL );

The following schema classes will have a DeepCopy function added to their class definition.

    FdoAssociationPropertyDefinition
    FdoClass
    FdoClassDefinition
    FdoClassCollection
    FdoDataPropertyDefinition
    FdoDataPropertyDefinitionCollection
    FdoFeatureClass
    FdoFeatureClassCollection
    FdoFeatureSchema
    FdoFeatureSchemaCollection
    FdoGeometricPropertyDefinition
    FdoObjectPropertyDefinition
    FdoPropertyDefinition
    FdoPropertyDefinitionCollection
    FdoNetworkClass
    FdoNetworkFeatureClass
    FdoNetworkLayerClass
    FdoNetworkLinkFeatureClass
    FdoNetworkNodeFeatureClass
    FdoRasterPropertyDefinition
    FdoReadOnlyDataPropertyDefinitionCollection
    FdoReadOnlyPropertyDefinitionCollection
    FdoSchemaCollection
    FdoTopoFeaturePropertyDefinition
    FdoTopoGeometryPropertyDefinition

NOTE: This list may have to be expanded depending on additional requirements

Example Implementation

The following example demonstrates how the DeepCopy method might be implemented for class FdoFeatureSchema

FdoFeatureSchema * FdoFeatureSchema::DeepCopy( FdoSchemaCopyContext * context )
{
    FdoSchemaCopyContextP copyContext = FDO_SAFE_ADDREF(context);
    if (copyContext == NULL) {
        copyContext = FdoSchemaCopyContext::Create();
    }

    FdoFeatureSchemaP retSchema = localSchemaContext->FindSchemaElement(this);
    if (retSchema != NULL) {
        return FDO_SAFE_ADDREF(retSchema.p);
    }

    FdoFeatureSchemaP clonedSchema = FdoFeatureSchema::Create(
          GetName(), 
          GetDescription());

    FdoInt32 length = 0;
    FdoSADP sourceAttributes = this->GetAttributes ();
    FdoSADP copyAttributes = clonedSchema->GetAttributes ();
    FdoString** sourceAttributeNames = sourceAttributes->GetAttributeNames (length);

    for (FdoInt32 i = 0; i < length; i++) {
        FdoString* name = sourceAttributeNames[i];
        FdoString* value = sourceAttributes->GetAttributeValue (name)
        copyAttributes->Add (name, value);
    }

    FdoClassesP classes = schema->GetClasses();
    FdoClassesP newClasses = clonedSchema->GetClasses();

    for (FdoInt32 i=0; i<classes->GetCount(); i++) {
        FdoClassDefinitionP class = classes->GetItem(i);
        FdoClassDefinitionP newClass = class->DeepCopy(copyContext);
        newClasses->Add(newClass);
    }

    clonedSchema->AcceptChanges();
    copyContext->InsertSchemaElement(this, clonedSchema);

    return FDO_SAFE_ADDREF(clonedSchema.p);
}
Example Usage

The following example demonstrates how the DeepCopy method might be used by a client such as the SDF Provider.

FdoClassDefinition* CloneAndPruneClass(
       FdoClassDefinition *classDef, 
       FdoIdentifierCollection *ids, 
       FdoPropertyDefinitionCollection* computedProps)
{
    // Create a copy context
    FdoPtr<FdoSchemaCopyContext> copyContext = NULL;
    if (ids != NULL && ids->GetCount() > 0) {
        copyContext = FdoSchemaCopyContext::Create(ids);
    }
    
    // Clone the class definition, copying only the class identifiers  
    // listed in the 'ids' collection
    FdoClassDefinitionP classDefPruned = classDef->DeepCopy(copyContext);
    FdoPropertiesP properties = classDefPruned->GetProperties ();

    // If there are additional computed properties that
    // need to be added to the cloned class definition
    if (computedProps != NULL) {
        // Add the computed properties to the class
        for (GdoInt32 i=0; i<computedProps->GetCount(); i++) {
            FdoPtr<FdoPropertyDefinition> computedProp = computedProps->GetItem(i);
            properties->Add(pd);
        }
    }

    // Returned the pruned class definition that also
    // includes the referenced computed properties
    return FDO_SAFE_ADDREF(classDefPruned.p);
}
Note: See TracWiki for help on using the wiki.