[mapguide-commits] r6853 - in branches/2.4/MgDev/Desktop: MapViewer MgDesktop/Services MgDesktop/Services/Feature UnitTest

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Thu Jul 5 08:27:56 PDT 2012


Author: jng
Date: 2012-07-05 08:27:56 -0700 (Thu, 05 Jul 2012)
New Revision: 6853

Modified:
   branches/2.4/MgDev/Desktop/MapViewer/MgMapViewer.cs
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FdoConnectionPool.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/GwsConnectionPool.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/ResourceService.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/ResourceService.h
   branches/2.4/MgDev/Desktop/UnitTest/TestFeatureService.cpp
   branches/2.4/MgDev/Desktop/UnitTest/TestFeatureService.h
Log:
mg-desktop updates:
 - #2057: Fix NullReferenceException on mouse wheel scrolling when no map is loaded
 - #2055: Clear existing selection before selection rendering whether a selection is made or not
 - #2054: Fix GetClasses and GetClassDefinition to work with Extended Feature Classes
 - Extract out the connection booting and cache flushing code into a separate MgdResourceService::ReleasePotentialLocks() method
 - Fix crashy behaviour in Release() in our GwsConnectionPool implementation. Returning a value from a member to a disposed pointer isn't exactly a good idea.

Modified: branches/2.4/MgDev/Desktop/MapViewer/MgMapViewer.cs
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/MgMapViewer.cs	2012-07-05 13:16:54 UTC (rev 6852)
+++ branches/2.4/MgDev/Desktop/MapViewer/MgMapViewer.cs	2012-07-05 15:27:56 UTC (rev 6853)
@@ -2309,7 +2309,12 @@
             sw.Stop();
             Trace.TraceInformation("Selection processing completed in {0}ms", sw.ElapsedMilliseconds);
 #endif
-
+            //This selection may result in nothing, so we invalidate the selection image beforehand
+            if (_selectionImage != null)
+            {
+                _selectionImage.Dispose();
+                _selectionImage = null;
+            }
             RenderSelection(true); //This is either async or queued up. Either way do this before firing off selection changed
             var handler = this.SelectionChanged;
             if (handler != null)

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FdoConnectionPool.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FdoConnectionPool.h	2012-07-05 13:16:54 UTC (rev 6852)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FdoConnectionPool.h	2012-07-05 15:27:56 UTC (rev 6853)
@@ -23,7 +23,7 @@
     STRING ProviderName;
 };
 
-class MgFdoConnectionPool
+class MG_DESKTOP_API MgFdoConnectionPool //Needs to be exported for unit testing code
 {
 public:
     static void Initialize(MgConfiguration* config);

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/GwsConnectionPool.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/GwsConnectionPool.cpp	2012-07-05 13:16:54 UTC (rev 6852)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/GwsConnectionPool.cpp	2012-07-05 15:27:56 UTC (rev 6853)
@@ -55,9 +55,11 @@
 {
     m_iRefCount --;
     assert (m_iRefCount >= 0);
-    if (m_iRefCount == 0)
-        Dispose ();
-    return m_iRefCount;
+    if (0 != m_iRefCount)
+        return m_iRefCount;
+
+    Dispose ();
+    return 0;
 }
 void MgGwsConnectionPool::Dispose ()
 {

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp	2012-07-05 13:16:54 UTC (rev 6852)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp	2012-07-05 15:27:56 UTC (rev 6853)
@@ -1382,7 +1382,7 @@
 
 MgFeatureSchemaCollection* MgdFeatureService::DescribeSchema(MgResourceIdentifier* resource,
                                                              CREFSTRING schemaName,
-                                                             MgStringCollection* classNames,
+                                                             MgStringCollection* findClassNames,
                                                              bool serialize) 
 { 
 	CHECK_FEATURE_SOURCE_ARGUMENT(resource, L"MgdFeatureService::DescribeSchema");
@@ -1392,8 +1392,38 @@
     MG_FEATURE_SERVICE_TRY()
 
     MgFeatureServiceCache* cache = MgFeatureServiceCache::GetInstance();
-    fsCollection = cache->GetSchemas(resource, schemaName, classNames, serialize);
+    fsCollection = cache->GetSchemas(resource, schemaName, findClassNames, serialize);
 
+    Ptr<MgFeatureSourceCacheItem> fsCache = cache->GetFeatureSource(resource);
+    MdfModel::FeatureSource* featureSource = fsCache->Get();
+    CHECKNULL(featureSource, L"MgdFeatureService::DescribeSchema");
+    MdfModel::ExtensionCollection* extensions = featureSource->GetExtensions();
+    CHECKNULL(extensions, L"MgdFeatureService::DescribeSchema");
+    int extensionCount = extensions->GetCount();
+
+    //Weed out extended class names because FDO won't know anything about them
+    Ptr<MgStringCollection> classNames;
+    if (NULL != findClassNames)
+    {
+        classNames = new MgStringCollection();
+        for (INT32 i = 0; i < findClassNames->GetCount(); i++)
+        {
+            STRING clsName = findClassNames->GetItem(i);
+            bool bIsExtendedClassName = false;
+            for (INT32 j = 0; j < extensionCount; j++)
+            {
+                MdfModel::Extension* extension = extensions->GetAt(i);
+                CHECKNULL(extension, L"MgdFeatureService::DescribeSchema");
+                STRING extName = (STRING)extension->GetName();
+                if (clsName == extName)
+                    bIsExtendedClassName = true;
+            }
+
+            if (!bIsExtendedClassName)
+                classNames->Add(clsName);
+        }
+    }
+
     if (NULL == fsCollection.p)
     {
         fsCollection = new MgFeatureSchemaCollection();
@@ -1409,7 +1439,6 @@
         //
         // A new MgFeatureSchema needs to be created for each primary schema in FDO schemas.
         //
-
         Ptr<MgFeatureSchema> schema;
         Ptr<MgClassDefinitionCollection> classCol;
 
@@ -1459,15 +1488,6 @@
             //
             // A new MgClassDefinition needs to be created for each extension and added to the MgClassCollection
             //
-
-            Ptr<MgFeatureSourceCacheItem> fsCache = cache->GetFeatureSource(resource);
-
-            MdfModel::FeatureSource* featureSource = fsCache->Get();
-            CHECKNULL(featureSource, L"MgdFeatureService::DescribeSchema");
-            MdfModel::ExtensionCollection* extensions = featureSource->GetExtensions();
-            CHECKNULL(extensions, L"MgdFeatureService::DescribeSchema");
-            int extensionCount = extensions->GetCount();
-
             for (int i = 0; i < extensionCount; i++)
             {
                 Ptr<MgClassDefinition> extClassDefinition;
@@ -1698,39 +1718,27 @@
                                             mpdc->Add(propDef);
                                         }
                                     }
-
                                     break;
-
                                 }  // end loop thru secondary class collection
-
                                 break;
-
                             }  // end loop thru secondary schemas
                         }
                         else
                         {
                             throw new MgConnectionFailedException(L"MgdFeatureService::DescribeSchema", __LINE__, __WFILE__, NULL, L"", NULL);
                         }
-
                     }  // end if (NULL != secFeatureSource)
-
                 }  // end loop thru all attribute relates (joins)
-
                 if (!extensionName.empty())
                 {
                     extClassDefinition->SetName(extensionName);
                 }
-
                 // Add the extension class definition to the MgClassDefinitionCollection
                 classCol->Add(extClassDefinition);
-
             }  // Repeat for all extensions
-
             // Add the schema to the MgFeatureSchemaCollection
             fsCollection->Add(schema);
-
         }  // End loop thru all schemas
-
         cache->SetSchemas(resource, schemaName, classNames, serialize, fsCollection.p);
     }
     else
@@ -5636,6 +5644,8 @@
     Ptr<MgFeatureConnection> connWrap = new MgFeatureConnection(resource);
 	FdoPtr<FdoIConnection> conn = connWrap->GetConnection();
 
+    STRING theSchemaName = schemaName;
+
 	if (SupportsPartialSchemaDiscovery(conn))
 	{
 		FdoPtr<FdoIGetClassNames> fetch = (FdoIGetClassNames*)conn->CreateCommand(FdoCommandType_GetClassNames);
@@ -5671,6 +5681,49 @@
 		classNames = names;
 	}
 
+    //In case an empty schema name was specified, get the schema name
+    //from the first result.
+    if (theSchemaName.empty())
+    {
+        INT32 clsCount = classNames->GetCount();
+        if (clsCount > 0)
+        {
+            for (INT32 i = 0; i < clsCount; i++)
+            {
+                STRING qn = classNames->GetItem(i);
+                STRING sn;
+                STRING cn;
+                MgUtil::ParseQualifiedClassName(qn, sn, cn);
+                
+                theSchemaName = sn;
+                break;
+            }
+        }
+    }
+
+    MgFeatureServiceCache* cache = MgFeatureServiceCache::GetInstance();
+    // Add extended feature class names
+    Ptr<MgFeatureSourceCacheItem> fsCache = cache->GetFeatureSource(resource);
+    MdfModel::FeatureSource* featureSource = fsCache->Get();
+    CHECKNULL(featureSource, L"MgdFeatureService::GetClasses");
+    MdfModel::ExtensionCollection* extensions = featureSource->GetExtensions();
+    CHECKNULL(extensions, L"MgdFeatureService::GetClasses");
+    int extensionCount = extensions->GetCount();
+    for (int i = 0; i < extensionCount; i++)
+    {
+        MdfModel::Extension* extension = extensions->GetAt(i);
+        CHECKNULL(extension, L"MgdFeatureService::GetClasses");
+
+        // Get the extension name
+        STRING extensionName = (STRING)extension->GetName();
+
+        STRING extendedClassName = theSchemaName;
+        extendedClassName += L":";
+        extendedClassName += extensionName;
+
+        classNames->Add(extendedClassName);
+    }
+
     // Successful operation
     MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
 

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.h	2012-07-05 13:16:54 UTC (rev 6852)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.h	2012-07-05 15:27:56 UTC (rev 6853)
@@ -272,7 +272,7 @@
 											CREFSTRING coordinateSystem,
 											bool withLock,
                                             bool asScrollable);
-	
+
 	bool ContainsUdf(MgFeatureConnection* conn, FdoExpression* expression);
 	bool IsCustomFunction(FdoFunction* fdoFunc);
 	MgReader* GetCustomReader(MgReader* reader, FdoFunction* customFunc, CREFSTRING propertyName);

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.cpp	2012-07-05 13:16:54 UTC (rev 6852)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.cpp	2012-07-05 15:27:56 UTC (rev 6853)
@@ -2017,8 +2017,9 @@
     TransformCacheMap transformCache;
 
     MG_TRY()
-
+#ifdef _DEBUG
     ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) RenderForSelection(): ** START **\n")));
+#endif
     if (NULL == map || (NULL == geometry && featureFilter.empty()))
         throw new MgNullArgumentException(L"MgServerRenderingService.RenderForSelection", __LINE__, __WFILE__, NULL, L"", NULL);
 
@@ -2102,9 +2103,9 @@
     {
         //find the layer we need to select features from
         Ptr<MgLayerBase> layer = layers->GetItem(p);
-
+    #ifdef _DEBUG
         ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) RenderForSelection(): Layer: %W  Selectable:%W  Visible: %W\n"), layer->GetName().c_str(), layer->GetSelectable()? L"True" : L"False", layer->IsVisibleAtScale(scale)? L"True" : L"False"));
-
+    #endif
         //do this first - this check is fast
         if (bOnlySelectableLayers && !layer->GetSelectable())
             continue;
@@ -2139,8 +2140,9 @@
         //we can only do geometric query selection for vector layers
         if (vl)
         {
+        #ifdef _DEBUG
             ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) RenderForSelection(): Layer: %W  Vector Layer\n"), layer->GetName().c_str()));
-
+        #endif
             //check to see if we want even layers that aren't visible at the current scale
             if (!bOnlyVisibleLayers)
             {
@@ -2370,7 +2372,9 @@
     }
 
     selRenderer->EndMap();
+#ifdef _DEBUG
     ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) RenderForSelection(): ** END **\n")));
+#endif
 
     MG_CATCH(L"MgServerRenderingService.RenderForSelection")
 

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/ResourceService.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/ResourceService.cpp	2012-07-05 13:16:54 UTC (rev 6852)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/ResourceService.cpp	2012-07-05 15:27:56 UTC (rev 6853)
@@ -298,16 +298,8 @@
     if (NULL != content)
     {
 	    Ptr<MgByteSink> sink = new MgByteSink(content);
-	    sink->ToFile(path);
-
-        if (resource->GetResourceType() == MgResourceType::FeatureSource)
-        {
-            //Invalidate any cached information
-            MgFeatureServiceCache* cache = MgFeatureServiceCache::GetInstance();
-            cache->RemoveEntry(resource);
-            //Boot pooled connections
-            MgFdoConnectionPool::PurgeCachedConnections(resource);
-        }
+        sink->ToFile(path);
+        ReleasePotentialLocks(resource);
     }
 
     // Successful operation
@@ -344,26 +336,8 @@
     CHECKARGUMENTNULL(resource, L"MgdResourceService::DeleteResource");
     if (ResourceExists(resource))
     {
-        if (resource->GetResourceType() == MgResourceType::FeatureSource)
-        {
-            //Invalidate any cached information
-            MgFeatureServiceCache* cache = MgFeatureServiceCache::GetInstance();
-            cache->RemoveEntry(resource);
-            //Boot pooled connections to ensure no locks are held (technically,
-            //the pooled connections are closed, but just to play safe)
-            MgFdoConnectionPool::PurgeCachedConnections(resource);
-        }
-        else if (resource->GetResourceType() == MgResourceType::Folder)
-        {
-            //TODO: We obviously need a fine-grained version instead of going nuclear
-            MgFeatureServiceCache* cache = MgFeatureServiceCache::GetInstance();
-            cache->Clear();
-            //Boot pooled connections to ensure no locks are held (technically,
-            //the pooled connections are closed, but just to play safe)
-            MgFdoConnectionPool::PurgeCachedConnectionsUnderFolder(resource);
-        }
-
-	    STRING contentPath = ResolveContentPath(resource);
+        ReleasePotentialLocks(resource);
+        STRING contentPath = ResolveContentPath(resource);
 	    STRING dataPath = ResolveDataPath(resource);
 	    if (MgFileUtil::IsFile(contentPath))
 	    {
@@ -400,6 +374,27 @@
     MG_RESOURCE_SERVICE_THROW()
 }
 
+void MgdResourceService::ReleasePotentialLocks(MgResourceIdentifier* resource)
+{
+    CHECKARGUMENTNULL(resource, L"MgdResourceService::DeleteResource");
+    if (resource->GetResourceType() == MgResourceType::FeatureSource)
+    {
+        //Invalidate any cached information
+        MgFeatureServiceCache* cache = MgFeatureServiceCache::GetInstance();
+        cache->RemoveEntry(resource);
+        //Boot pooled connections to ensure no locks are held
+        MgFdoConnectionPool::PurgeCachedConnections(resource);
+    }
+    else if (resource->GetResourceType() == MgResourceType::Folder)
+    {
+        //TODO: We obviously need a fine-grained version instead of going nuclear
+        MgFeatureServiceCache* cache = MgFeatureServiceCache::GetInstance();
+        cache->Clear();
+        //Boot pooled connections to ensure no locks are held
+        MgFdoConnectionPool::PurgeCachedConnectionsUnderFolder(resource);
+    }
+}
+
 void MgdResourceService::CopyResource(MgResourceIdentifier* sourceResource, MgResourceIdentifier* destResource, bool overwrite) 
 { 
     MG_LOG_OPERATION_MESSAGE(L"CopyResource");
@@ -728,6 +723,7 @@
     if (dataName.empty())
         throw new MgNullArgumentException(L"MgdResourceService::DeleteResourceData", __LINE__, __WFILE__, NULL, L"", NULL);
 
+    ReleasePotentialLocks(resource);
 	STRING path = ResolveDataPath(resource);
 	path += dataName;
 

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/ResourceService.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/ResourceService.h	2012-07-05 13:16:54 UTC (rev 6852)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/ResourceService.h	2012-07-05 15:27:56 UTC (rev 6853)
@@ -97,6 +97,7 @@
 	virtual void Dispose() { delete this; }
 
 private:
+    void ReleasePotentialLocks(MgResourceIdentifier* resource);
     static bool ListDirectories(MgStringCollection* directoryNames, CREFSTRING path);
     void WriteResourceFolderEntry(REFSTRING xml, INT32 maxDepth, STRING type, MgResourceIdentifier* resId, CREFSTRING enumeratedFolderId = L"");
     void WriteResourceDocumentEntry(REFSTRING xml, MgResourceIdentifier* resId);
@@ -105,6 +106,7 @@
 	STRING m_libraryDataPath;
 	STRING m_sessionContentPath;
 	STRING m_sessionDataPath;
+    STRING m_schemaPath;
 };
 
 #endif
\ No newline at end of file

Modified: branches/2.4/MgDev/Desktop/UnitTest/TestFeatureService.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/UnitTest/TestFeatureService.cpp	2012-07-05 13:16:54 UTC (rev 6852)
+++ branches/2.4/MgDev/Desktop/UnitTest/TestFeatureService.cpp	2012-07-05 15:27:56 UTC (rev 6853)
@@ -17,6 +17,7 @@
 
 #include "Services/Feature/FeatureUtil.h"
 #include "MgDesktop.h"
+#include "Services/Feature/FdoConnectionPool.h"
 #include "TestFeatureService.h"
 #include "CppUnitExtensions.h"
 #include "Fdo.h"
@@ -261,7 +262,18 @@
                 __LINE__, __WFILE__, NULL, L"", NULL);
         }
 
-        /*
+
+#ifdef DEBUG
+        ACE_DEBUG((LM_INFO, ACE_TEXT("\nConnection Pool status: \n\n")));
+        std::vector<PoolCacheEntry*> entries;
+        MgFdoConnectionPool::GetCacheInfo(entries);
+        for (std::vector<PoolCacheEntry*>::iterator it = entries.begin(); it != entries.end(); it++)
+        {
+            STRING resId = (*it)->ResourceId;
+            ACE_DEBUG((LM_INFO, ACE_TEXT(" - %W (%d Open, %d Closed)\n"), resId.c_str(), (*it)->OpenCount, (*it)->ClosedCount));
+        }
+#endif
+
         // delete the feature sources definition
         Ptr<MgResourceIdentifier> fsres1 = new MgResourceIdentifier(L"Library://UnitTests/Data/Sheboygan_Parcels.FeatureSource");
         pService->DeleteResource(fsres1);
@@ -283,9 +295,12 @@
 
         Ptr<MgResourceIdentifier> fsres7 = new MgResourceIdentifier(L"Library://UnitTests/Data/Sheboygan_Parcels_Writable.FeatureSource");
         pService->DeleteResource(fsres7);
-        */
-        Ptr<MgResourceIdentifier> folder = new MgResourceIdentifier(L"Library://UnitTests/");
-        pService->DeleteResource(folder);
+
+        Ptr<MgResourceIdentifier> fsres8 = new MgResourceIdentifier(L"Library://UnitTests/Data/FdoJoin.FeatureSource");
+        pService->DeleteResource(fsres8);
+        
+        //Ptr<MgResourceIdentifier> folder = new MgResourceIdentifier(L"Library://UnitTests/");
+        //pService->DeleteResource(folder);
     }
     catch (MgException* e)
     {
@@ -2604,6 +2619,125 @@
 ///----------------------------------------------------------------------------
 /// Test Case Description:
 ///
+/// This test case exercises schema description APIs against a feature source
+/// with Extended Feature Classes
+///----------------------------------------------------------------------------
+void TestFeatureService::TestCase_ExtendedFeatureClass()
+{
+    try
+    {
+        Ptr<MgServiceFactory> fact = new MgServiceFactory();
+        Ptr<MgFeatureService> pService = dynamic_cast<MgFeatureService*>(fact->CreateService(MgServiceType::FeatureService));
+        if (pService == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestFeatureService.TestCase_ExtendedFeatureClass",
+                __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgResourceIdentifier> lFeatureSource = new MgResourceIdentifier(L"Library://UnitTests/Data/TestChainedInner1ToManyJoin.FeatureSource");
+
+        Ptr<MgFeatureReader> reader = pService->SelectFeatures(lFeatureSource, L"Ext1", NULL);
+
+        Ptr<MgFeatureSchemaCollection> schemas;
+        Ptr<MgFeatureSchema> schema;
+        //With GetClasses
+        Ptr<MgStringCollection> classNames = pService->GetClasses(lFeatureSource, L"");
+        CPPUNIT_ASSERT(classNames->GetCount() > 0);
+        bool bFound = false;
+        for (INT32 i = 0; i < classNames->GetCount(); i++)
+        {
+            STRING name = classNames->GetItem(i);
+            if (name.find(L"Ext1") != STRING::npos)
+            {
+                bFound = true;
+                break;
+            }
+        }
+        CPPUNIT_ASSERT(bFound);
+
+        //With 1st variation of DescribeSchema()
+        schemas = pService->DescribeSchema(lFeatureSource, L"");
+        CPPUNIT_ASSERT(NULL != schemas.p);
+        CPPUNIT_ASSERT(1 == schemas->GetCount());
+        schema = schemas->GetItem(0);
+        Ptr<MgClassDefinitionCollection> classes = schema->GetClasses();
+        bFound = false;
+        for (INT32 i = 0; i < classes->GetCount(); i++)
+        {
+            Ptr<MgClassDefinition> klass = classes->GetItem(i);
+            if (klass->GetName() == L"Ext1")
+            {
+                bFound = true;
+                break;
+            }
+        }
+        CPPUNIT_ASSERT(bFound);
+
+        //1st variation of DescribeSchema() with the actual parent schema name
+        schemas = pService->DescribeSchema(lFeatureSource, L"SHP_Schema");
+        CPPUNIT_ASSERT(NULL != schemas.p);
+        CPPUNIT_ASSERT(1 == schemas->GetCount());
+        schema = schemas->GetItem(0);
+        classes = schema->GetClasses();
+        bFound = false;
+        for (INT32 i = 0; i < classes->GetCount(); i++)
+        {
+            Ptr<MgClassDefinition> klass = classes->GetItem(i);
+            if (klass->GetName() == L"Ext1")
+            {
+                bFound = true;
+                break;
+            }
+        }
+        CPPUNIT_ASSERT(bFound);
+        Ptr<MgStringCollection> findClassNames = new MgStringCollection();
+        findClassNames->Add(L"Ext1");
+
+        //2nd variation of DescribeSchema()
+        schemas = pService->DescribeSchema(lFeatureSource, L"SHP_Schema", findClassNames);
+        CPPUNIT_ASSERT(NULL != schemas.p);
+        CPPUNIT_ASSERT(1 == schemas->GetCount());
+        schema = schemas->GetItem(0);
+        classes = schema->GetClasses();
+        bFound = false;
+        for (INT32 i = 0; i < classes->GetCount(); i++)
+        {
+            Ptr<MgClassDefinition> klass = classes->GetItem(i);
+            if (klass->GetName() == L"Ext1")
+            {
+                bFound = true;
+                break;
+            }
+        }
+        CPPUNIT_ASSERT(bFound);
+
+        Ptr<MgClassDefinition> clsDef = pService->GetClassDefinition(lFeatureSource, L"SHP_Schema", L"Ext1");
+        CPPUNIT_ASSERT(NULL != clsDef.p);
+    }
+    catch(MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        STRING st = e->GetStackTrace(TEST_LOCALE);
+        message += L"\n" + st;
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(FdoException* e)
+    {
+        STRING message = L"FdoException occurred: ";
+        message += e->GetExceptionMessage();
+        FDO_SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
 /// This test case exercises the FDO join optimization
 ///----------------------------------------------------------------------------
 void TestFeatureService::TestCase_JoinFdoFeatures()

Modified: branches/2.4/MgDev/Desktop/UnitTest/TestFeatureService.h
===================================================================
--- branches/2.4/MgDev/Desktop/UnitTest/TestFeatureService.h	2012-07-05 13:16:54 UTC (rev 6852)
+++ branches/2.4/MgDev/Desktop/UnitTest/TestFeatureService.h	2012-07-05 15:27:56 UTC (rev 6853)
@@ -43,6 +43,7 @@
     CPPUNIT_TEST(TestCase_SelectFeaturesTransformed);
     CPPUNIT_TEST(TestCase_SelectScrollable);
     CPPUNIT_TEST(TestCase_SelectAggregate);
+    CPPUNIT_TEST(TestCase_ExtendedFeatureClass);
     CPPUNIT_TEST(TestCase_InsertFeatures);
     CPPUNIT_TEST(TestCase_InsertFeaturesBatch);
     CPPUNIT_TEST(TestCase_UpdateFeatures);
@@ -105,6 +106,7 @@
     void TestCase_DeleteFeatures();
     void TestCase_ExecuteSqlQuery();
     void TestCase_ExecuteSqlNonQuery();
+    void TestCase_ExtendedFeatureClass();
     void TestCase_GetSpatialContexts();
     void TestCase_GetLongTransactions();
     void TestCase_SetLongTransaction();



More information about the mapguide-commits mailing list