[mapguide-commits] r6846 - in branches/2.4/MgDev: Common/PlatformBase/Services Server/src/Services/Feature Server/src/UnitTesting

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Wed Jul 4 05:10:49 PDT 2012


Author: jng
Date: 2012-07-04 05:10:49 -0700 (Wed, 04 Jul 2012)
New Revision: 6846

Modified:
   branches/2.4/MgDev/Common/PlatformBase/Services/FeatureService.h
   branches/2.4/MgDev/Server/src/Services/Feature/OpUpdateFeatures.cpp
   branches/2.4/MgDev/Server/src/UnitTesting/TestFeatureService.cpp
   branches/2.4/MgDev/Server/src/UnitTesting/TestFeatureService.h
Log:
#649: Log non-transactional command execution failures in MgFeatureService::UpdateFeatures(). Also clean up the API documentation relating to this method. Basically, for calls to this method without a transaction, the calling code should inspect the returned MgPropertyCollection for any instances of MgStringProperty. Any such instances will contain the exception message relating to that particular command. If the resulting MgPropertyCollection contains no MgStringProperty instances and the method itself did not throw any exceptions, the operation as a whole is a success.

Modified: branches/2.4/MgDev/Common/PlatformBase/Services/FeatureService.h
===================================================================
--- branches/2.4/MgDev/Common/PlatformBase/Services/FeatureService.h	2012-07-04 10:21:40 UTC (rev 6845)
+++ branches/2.4/MgDev/Common/PlatformBase/Services/FeatureService.h	2012-07-04 12:10:49 UTC (rev 6846)
@@ -870,11 +870,21 @@
     ///   <li>If the command is of type MgLockFeatures, the property
     ///     type is MgPropertyType::Feature, and its value is the number
     ///     of features locked.</li>
-    ///   <li>If the command is of type MgUnLockFeatures, the property
+    ///   <li>If the command is of type MgUnlockFeatures, the property
     ///     type is MgPropertyType::Int32, and its value is the number of
     ///     features unlocked.</li>
+    ///   <li>For any of the above commands, if the property type is 
+    ///     MgPropertyType::String, it indicates an exception had occurred
+    ///     for that particular command, and its value is the exception message.
+    ///     This only applies when the operation is not using a transaction</li>
     /// </ul>
     ///
+    /// \remarks
+    /// If useTransaction is false, this method will not throw any exceptions on command execution failure. 
+    /// In such cases, you need to inspect the returned collection for any instances of MgStringProperty
+    /// Such instances will contain the exception message for the corresponding command that was
+    /// executed
+    ///
     /// \exception MgFeatureServiceException
     /// \exception MgInvalidArgumentException
     /// \exception MgInvalidOperationException
@@ -943,11 +953,21 @@
     ///   <li>If the command is of type MgLockFeatures, the property
     ///     type is MgPropertyType::Feature, and its value is the number
     ///     of features locked.</li>
-    ///   <li>If the command is of type MgUnLockFeatures, the property
+    ///   <li>If the command is of type MgUnlockFeatures, the property
     ///     type is MgPropertyType::Int32, and its value is the number of
     ///     features unlocked.</li>
+    ///   <li>For any of the above commands, if the property type is 
+    ///     MgPropertyType::String, it indicates an exception had occurred
+    ///     for that particular command, and its value is the exception message.
+    ///     This only applies when the operation is not using a transaction</li>
     /// </ul>
     ///
+    /// \remarks
+    /// If transaction is NULL, this method will not throw any exceptions on command execution failure. 
+    /// In such cases, you need to inspect the returned collection for any instances of MgStringProperty
+    /// Such instances will contain the exception message for the corresponding command that was
+    /// executed
+    ///
     /// \exception MgFeatureServiceException
     /// \exception MgInvalidArgumentException
     /// \exception MgInvalidOperationException

Modified: branches/2.4/MgDev/Server/src/Services/Feature/OpUpdateFeatures.cpp
===================================================================
--- branches/2.4/MgDev/Server/src/Services/Feature/OpUpdateFeatures.cpp	2012-07-04 10:21:40 UTC (rev 6845)
+++ branches/2.4/MgDev/Server/src/Services/Feature/OpUpdateFeatures.cpp	2012-07-04 12:10:49 UTC (rev 6846)
@@ -54,6 +54,7 @@
 {
     ACE_DEBUG((LM_DEBUG, ACE_TEXT("  (%t) MgOpUpdateFeatures::Execute()\n")));
 
+    STRING partialFailureMsg;
     MG_LOG_OPERATION_MESSAGE(L"UpdateFeatures");
 
     MG_FEATURE_SERVICE_TRY()
@@ -92,6 +93,22 @@
 
         // Write the response
         EndExecution(rowsAffected);
+
+        // #649: Exceptions are only thrown in transactional cases (which will never reach here). For non-transactional cases, 
+        // we check for any MgStringProperty instances. These are "serialized" FDO exception messages indicating failure for that 
+        // particular command. We can't throw for non-transactional cases, instead we put the onus on the consuming caller to do 
+        // the same check we are doing here.
+        for (INT32 i = 0; i < rowsAffected->GetCount(); i++) 
+        {
+            Ptr<MgProperty> prop = rowsAffected->GetItem(i);
+            if (prop->GetPropertyType() == MgPropertyType::String)
+            {
+                MgStringProperty* sprop = static_cast<MgStringProperty*>(prop.p);
+                //One is enough to flag partial failure (should we go through all of them?)
+                partialFailureMsg = sprop->GetValue();
+                break;
+            }
+        }
     }
     else
     {
@@ -105,15 +122,26 @@
             __LINE__, __WFILE__, NULL, L"", NULL);
     }
 
-    // Successful operation
-    MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
+    if (partialFailureMsg.empty())
+    {
+        // Successful operation
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
+    }
 
     MG_FEATURE_SERVICE_CATCH(L"MgOpUpdateFeatures.Execute")
 
-    if (mgException != NULL)
+    if (mgException != NULL || !partialFailureMsg.empty())
     {
         // Failed operation
         MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Failure.c_str());
+        // Only thrown exceptions are logged, so for this partial failure to be logged into Error.log it needs to be
+        // wrapped in an MgException to be thrown at the end of this method
+        if (mgException == NULL && !partialFailureMsg.empty())
+        {
+            MgStringCollection args;
+            args.Add(partialFailureMsg);
+            mgException = new MgFeatureServiceException(L"MgOpUpdateFeatures.Execute", __LINE__, __WFILE__, NULL, L"MgFormatInnerExceptionMessage", &args);
+        }
     }
 
     // Add access log entry for operation

Modified: branches/2.4/MgDev/Server/src/UnitTesting/TestFeatureService.cpp
===================================================================
--- branches/2.4/MgDev/Server/src/UnitTesting/TestFeatureService.cpp	2012-07-04 10:21:40 UTC (rev 6845)
+++ branches/2.4/MgDev/Server/src/UnitTesting/TestFeatureService.cpp	2012-07-04 12:10:49 UTC (rev 6846)
@@ -2758,3 +2758,69 @@
         throw;
     }
 }
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tests the correct response for a non-transactional failure
+/// in UpdateFeatures
+///----------------------------------------------------------------------------
+void TestFeatureService::TestCase_UpdateFeaturesPartialFailure()
+{
+    try
+    {
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        if(serviceManager == 0)
+        {
+            throw new MgNullReferenceException(L"TestFeatureService.TestCase_UpdateFeaturesPartialFailure", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgFeatureService> featSvc = dynamic_cast<MgFeatureService*>(serviceManager->RequestService(MgServiceType::FeatureService));
+        if (featSvc == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestFeatureService.TestCase_UpdateFeaturesPartialFailure",
+                __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgResourceIdentifier> fsId = new MgResourceIdentifier(L"Library://UnitTests/Data/Sheboygan_Parcels.FeatureSource");
+        Ptr<MgPropertyCollection> props = new MgPropertyCollection();
+        Ptr<MgInt32Property> idProp = new MgInt32Property(L"id", 0);
+        props->Add(idProp);
+        Ptr<MgInsertFeatures> insert = new MgInsertFeatures(L"Parcels1", props); //Bogus class name to trigger exception
+        Ptr<MgFeatureCommandCollection> cmds = new MgFeatureCommandCollection();
+        cmds->Add(insert);
+
+        Ptr<MgPropertyCollection> result = featSvc->UpdateFeatures(fsId, cmds, false);
+        CPPUNIT_ASSERT(result->GetCount() > 0);
+
+        bool bPartialFailure = false;
+        for (INT32 i = 0; i < result->GetCount(); i++)
+        {
+            Ptr<MgProperty> prop = result->GetItem(i);
+            if (prop->GetPropertyType() == MgPropertyType::String)
+            {
+                bPartialFailure = true;
+                break;
+            }
+        }
+
+        CPPUNIT_ASSERT(bPartialFailure);
+    }
+    catch(MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        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;
+    }
+}
\ No newline at end of file

Modified: branches/2.4/MgDev/Server/src/UnitTesting/TestFeatureService.h
===================================================================
--- branches/2.4/MgDev/Server/src/UnitTesting/TestFeatureService.h	2012-07-04 10:21:40 UTC (rev 6845)
+++ branches/2.4/MgDev/Server/src/UnitTesting/TestFeatureService.h	2012-07-04 12:10:49 UTC (rev 6846)
@@ -40,6 +40,7 @@
     CPPUNIT_TEST(TestCase_SelectFeatures);
     CPPUNIT_TEST(TestCase_SelectAggregate);
 //    CPPUNIT_TEST(TestCase_UpdateFeatures);
+    CPPUNIT_TEST(TestCase_UpdateFeaturesPartialFailure);
 //  TODO write test case when know how to make command collection
     CPPUNIT_TEST(TestCase_ExecuteSqlQuery);
     CPPUNIT_TEST(TestCase_ExecuteSqlNonQuery);
@@ -89,6 +90,7 @@
     void TestCase_SelectFeatures();
     void TestCase_SelectAggregate();
 //    void TestCase_UpdateFeatures();
+    void TestCase_UpdateFeaturesPartialFailure();
     void TestCase_ExecuteSqlQuery();
     void TestCase_ExecuteSqlNonQuery();
     void TestCase_GetSpatialContexts();



More information about the mapguide-commits mailing list