Opened 14 years ago

Closed 14 years ago

Last modified 14 years ago

#1119 closed defect (fixed)

MgSpatialContextReader shouldn't clear internal data when close

Reported by: christinebao Owned by: Christine Bao
Priority: medium Milestone: 2.2
Component: General Version: 2.0.2
Severity: trivial Keywords:
Cc: Bruce Dechant External ID: 1262439

Description

In MapGuide build 23.6 Query widget can't work.

Steps:

  1. Open one flexible web layout with Polygon layer in IE.
  2. Do Query on that layer.

Results:
No matched result returned.

Expected Results:
The matched result should be returned.

Attachments (2)

ClassDiagram.JPG (46.6 KB ) - added by christinebao 14 years ago.
SpatialContextReader.patch (642 bytes ) - added by christinebao 14 years ago.

Download all attachments as: .zip

Change History (7)

by christinebao, 14 years ago

Attachment: ClassDiagram.JPG added

comment:1 by christinebao, 14 years ago

Tech diagnosis:

The relationship of the classes


Brief code snippet to demo how they work


  1. MgSpatialContextReader* MgServerFeatureService::GetSpatialContexts( MgResourceIdentifier* resource, bool bActiveOnly) calles MgServerGetSpatialContexts to get the reader actually. And MgServerGetSpatialContexts has a cache (m_featureServiceCache) inside. This cache is based on resource id and its cache entry. If the cache contains the resource id, get its spatial context reader and return directly; if not a FDO command is executed to get the spatial context reader, and added to the cache. So later when requiring the spatial context reader again, the cached one will be returned directly.
MgSpatialContextReader* MgServerGetSpatialContexts::GetSpatialContexts(MgResourceIdentifier* resId)
{
    Ptr<MgSpatialContextReader> mgSpatialContextReader;

    MG_FEATURE_SERVICE_TRY()

    mgSpatialContextReader = m_featureServiceCache->GetSpatialContextReader(resId);

    if (NULL == mgSpatialContextReader.p)
    {
        // Connect to provider
        Ptr<MgServerFeatureConnection> msfc = new MgServerFeatureConnection(resId);

        // Connection must be open to retrieve a list of available contexts.
        if ((NULL != msfc.p) && ( msfc->IsConnectionOpen() ))
        {
            // The reference to the FDO connection from the MgServerFeatureConnection object must be cleaned up before the parent object
            // otherwise it leaves the FDO connection marked as still in use.
            FdoPtr<FdoIConnection> fdoConn = msfc->GetConnection();
            m_providerName = msfc->GetProviderName();

            Ptr<MgSpatialContextCacheItem> cacheItem = MgCacheManager::GetInstance()->GetSpatialContextCacheItem(resId);
            MgSpatialContextInfo* spatialContextInfo = cacheItem->Get();

            // Check whether command is supported by provider
            if (!msfc->SupportsCommand((INT32)FdoCommandType_GetSpatialContexts))
            {
                // TODO: specify which argument and message, once we have the mechanism
                STRING message = MgServerFeatureUtil::GetMessage(L"MgCommandNotSupported");
                throw new MgInvalidOperationException(L"MgServerGetSpatialContexts.GetSpatialContexts", __LINE__, __WFILE__, NULL, L"", NULL);
            }

            FdoPtr<FdoIGetSpatialContexts> fdoCommand = (FdoIGetSpatialContexts*)fdoConn->CreateCommand(FdoCommandType_GetSpatialContexts);
            CHECKNULL((FdoIGetSpatialContexts*)fdoCommand, L"MgServerGetSpatialContexts.GetSpatialContexts");

            // Execute the command
            FdoPtr<FdoISpatialContextReader> spatialReader = fdoCommand->Execute();
            CHECKNULL((FdoISpatialContextReader*)spatialReader, L"MgServerGetSpatialContexts.GetSpatialContexts");

            mgSpatialContextReader = new MgSpatialContextReader();
            while (spatialReader->ReadNext())
            {
                // Set providername for which spatial reader is executed
                mgSpatialContextReader->SetProviderName(m_providerName);

                Ptr<MgSpatialContextData> spatialData = GetSpatialContextData(spatialReader, spatialContextInfo);
                CHECKNULL((MgSpatialContextData*)spatialData, L"MgServerGetSpatialContexts.GetSpatialContexts");

                // Add spatial data to the spatialcontext reader
                mgSpatialContextReader->AddSpatialData(spatialData);
            }

            m_featureServiceCache->SetSpatialContextReader(resId, mgSpatialContextReader.p);
        }
        else
        {
            throw new MgConnectionFailedException(L"MgServerGetSpatialContexts.GetSpatialContexts()", __LINE__, __WFILE__, NULL, L"", NULL);
        }
    }
    else
    {
        MgCacheManager::GetInstance()->CheckPermission(resId, MgResourcePermission::ReadOnly);
    }

    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH_AND_THROW(resId, L"MgServerGetSpatialContexts.GetSpatialContexts")

    return mgSpatialContextReader.Detach();
}

  1. MgFeatureServiceCacheEntry is a cache entry which contains MgSpatialContextReader, and its Get/SetSpatialContextReader is simply a wrapper.
void MgFeatureServiceCacheEntry::SetSpatialContextReader(MgSpatialContextReader* spatialContextReader)
{
    m_spatialContextReader = SAFE_ADDREF(spatialContextReader);
}

MgSpatialContextReader* MgFeatureServiceCacheEntry::GetSpatialContextReader()
{
    return SAFE_ADDREF(m_spatialContextReader.p);
}

  1. MgSpatialContextReader, which we can get from API, contains a collection of MgSpatialContextData, and the reader will go through the data one by one when read next. It has AddSpatialData(…) function to initialize the MgSpatialContextData, which is called in MgServerGetSpatialContexts when first time added to cache. And it has a Close() function to clear the data.
void MgSpatialContextReader::Close()
{
    m_spatialContextCol.Clear();
}

INT32 MgSpatialContextReader::AddSpatialData(MgSpatialContextData* data)
{
    m_spatialContextCol.Add(data);
    return m_spatialContextCol.GetCount();
}

How the defect happens


  1. Open a Flexible web layout, and the function TransformCache* TransformCache::GetLayerToMapTransform(…) is called. It gets the MgSpatialContextReader. This is the first time when MgSpatialContextReader is required, and the FDO command is executed to initialize it. Then it’s added to the cache. However the reader is closed, making the internal data clear.
  2. Later another code in $MgDev\OS\Oem\fusion\widgets\Query\classes\query.php try to get the MgSpatialContextReader again. The cache contains the resource id and entry, then it returns a MgSpatialContextReader. However the internal data is empty, causing not able to get the spatial context any more.

comment:2 by christinebao, 14 years ago

How to fix:

The architecture for the readers is suppose to be:
Get reader
Use reader
Close reader

As the reader is cached inside, the Close() function shouldn't clear the internal data. Fixing is not to clear internal data when close:

void MgSpatialContextReader::Close()
{
}

MgSpatialContextReader::~MgSpatialContextReader()
{
    m_spatialContextCol.Clear();
}

by christinebao, 14 years ago

Attachment: SpatialContextReader.patch added

comment:4 by christinebao, 14 years ago

Resolution: fixed
Status: newclosed

comment:5 by brucedechant, 14 years ago

Fixed in submission r4307

Note: See TracTickets for help on using tickets.