[mapguide-commits] r8177 - in sandbox/jng/tiling: Common/MapGuideCommon/Services Common/PlatformBase/MapLayer Server/src/Services/Tile Server/src/UnitTesting

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Fri May 30 08:31:41 PDT 2014


Author: jng
Date: 2014-05-30 08:31:40 -0700 (Fri, 30 May 2014)
New Revision: 8177

Added:
   sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.cpp
   sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.h
Modified:
   sandbox/jng/tiling/Common/MapGuideCommon/Services/ProxyTileService.cpp
   sandbox/jng/tiling/Common/MapGuideCommon/Services/ProxyTileService.h
   sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.h
   sandbox/jng/tiling/Common/MapGuideCommon/Services/TileService.h
   sandbox/jng/tiling/Common/PlatformBase/MapLayer/LayerGroup.cpp
   sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.cpp
   sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.h
   sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj
   sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj.filters
   sandbox/jng/tiling/Server/src/Services/Tile/ServerTileServiceBuild.cpp
   sandbox/jng/tiling/Server/src/Services/Tile/TileCache.cpp
   sandbox/jng/tiling/Server/src/Services/Tile/TileCache.h
   sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.cpp
Log:
This submission performs open-heart surgery on the server tile service.

MgTileCache has been re-defined as an abstract class providing a similar interface to MgTileService which currently has one subclass: MgTileCacheDefault.

The new role of MgServerTileService is simply to instantiate the correct MgTileCache subclass instance and forward the calls to it.

MgTileCacheDefault is the amalgamation of the old implementations of MgServerTileService and MgTileCache, and provides the existing tile management logic for existing tiled Map Definitions.

This is done to allow for a TileSetDefinition-driven MgTileCache subclass in the near future, which the refactored MgServerTileService is ready to forward requests to when implemented.

Modified: sandbox/jng/tiling/Common/MapGuideCommon/Services/ProxyTileService.cpp
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/Services/ProxyTileService.cpp	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Common/MapGuideCommon/Services/ProxyTileService.cpp	2014-05-30 15:31:40 UTC (rev 8177)
@@ -260,3 +260,83 @@
 {
     m_connProp = SAFE_ADDREF(connProp);
 }
+
+//////////////////////////////////////////////////////////////////
+/// \brief
+/// Clears the entire tile cache for the given tile set.  Tiles for all base
+/// map layer groups and finite scales will be removed.
+///
+/// \param map
+/// Input
+/// Specifies the map whose tile cache will be cleared.
+///
+void MgProxyTileService::ClearCache(MgResourceIdentifier* tileSet)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                      // Connection
+                        MgCommand::knVoid,                              // Return type expected
+                        MgTileServiceOpId::ClearCache2,                 // Command Code
+                        1,                                              // No of arguments
+                        Tile_Service,                                   // Service Id
+                        BUILD_VERSION(3,0,0),                           // Operation version
+                        MgCommand::knObject, tileSet,                   // Argument#1
+                        MgCommand::knNone);                             // End of arguments
+
+    SetWarning(cmd.GetWarningObject());
+}
+
+//////////////////////////////////////////////////////////////////
+/// \brief
+/// Returns the default width of a tile.
+INT32 MgProxyTileService::GetDefaultTileSizeX(MgResourceIdentifier* tileSet)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                      // Connection
+                        MgCommand::knObject,                            // Return type expected
+                        MgTileServiceOpId::GetDefaultTileSizeX2,        // Command Code
+                        1,                                              // No of arguments
+                        Tile_Service,                                   // Service Id
+                        BUILD_VERSION(3,0,0),                           // Operation version
+                        MgCommand::knObject, tileSet,                   // Argument#1
+                        MgCommand::knNone);                             // End of arguments
+
+    SetWarning(cmd.GetWarningObject());
+
+    return cmd.GetReturnValue().val.m_i32;
+}
+
+//////////////////////////////////////////////////////////////////
+/// \brief
+/// Returns the default height of a tile.
+INT32 MgProxyTileService::GetDefaultTileSizeY(MgResourceIdentifier* tileSet)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                      // Connection
+                        MgCommand::knObject,                            // Return type expected
+                        MgTileServiceOpId::GetDefaultTileSizeY2,        // Command Code
+                        1,                                              // No of arguments
+                        Tile_Service,                                   // Service Id
+                        BUILD_VERSION(3,0,0),                           // Operation version
+                        MgCommand::knObject, tileSet,                   // Argument#1
+                        MgCommand::knNone);                             // End of arguments
+
+    SetWarning(cmd.GetWarningObject());
+
+    return cmd.GetReturnValue().val.m_i32;
+}
+
+MgByteReader* MgProxyTileService::GetTileProviders()
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                      // Connection
+                        MgCommand::knInt32,                             // Return type expected
+                        MgTileServiceOpId::GetTileProviders,            // Command Code
+                        0,                                              // No of arguments
+                        Tile_Service,                                   // Service Id
+                        BUILD_VERSION(3,0,0),                           // Operation version
+                        MgCommand::knNone);                             // End of arguments
+
+    SetWarning(cmd.GetWarningObject());
+
+    return (MgByteReader*)cmd.GetReturnValue().val.m_obj;
+}

Modified: sandbox/jng/tiling/Common/MapGuideCommon/Services/ProxyTileService.h
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/Services/ProxyTileService.h	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Common/MapGuideCommon/Services/ProxyTileService.h	2014-05-30 15:31:40 UTC (rev 8177)
@@ -101,6 +101,18 @@
 
     //////////////////////////////////////////////////////////////////
     /// \brief
+    /// Clears the entire tile cache for the given tile set.  Tiles for all base
+    /// map layer groups and finite scales will be removed.
+    ///
+    /// \param map
+    /// Input
+    /// Specifies the map whose tile cache will be cleared.
+    ///
+    /// \since 3.0
+    virtual void ClearCache(MgResourceIdentifier* tileSet);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
     /// Returns the default width of a tile.
     ///
     /// \return
@@ -117,6 +129,41 @@
     ///
     virtual INT32 GetDefaultTileSizeY();
 
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the default width of a tile.
+    ///
+    /// \param tileSet
+    /// Input
+    /// Specifies the resource id of the tile set
+    ///
+    /// \return
+    /// Default width of a tile in pixels.
+    ///
+    /// \since 3.0
+    virtual INT32 GetDefaultTileSizeX(MgResourceIdentifier* tileSet);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the default height of a tile.
+    ///
+    /// \param tileSet
+    /// Input
+    /// Specifies the resource id of the tile set
+    ///
+    /// \return
+    /// Default height of a tile in pixels.
+    ///
+    /// \since 3.0
+    virtual INT32 GetDefaultTileSizeY(MgResourceIdentifier* tileSet);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the list of available tile providers, along with supported connection parameters
+    ///
+    /// \since 3.0
+    virtual MgByteReader* GetTileProviders();
+
 INTERNAL_API:
 
     /////////////////////////////////////////////////////////////////

Modified: sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.h
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.h	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.h	2014-05-30 15:31:40 UTC (rev 8177)
@@ -27,11 +27,15 @@
 class MG_MAPGUIDE_API MgTileServiceOpId
 {
 INTERNAL_API:
-    static const int GetTile    = 0x1111E801;
-    static const int SetTile    = 0x1111E802;
-    static const int ClearCache = 0x1111E803;
+    static const int GetTile              = 0x1111E801;
+    static const int SetTile              = 0x1111E802;
+    static const int ClearCache           = 0x1111E803;
     static const int GetDefaultTileSizeX  = 0x1111E804;
     static const int GetDefaultTileSizeY  = 0x1111E805;
+    static const int ClearCache2          = 0x1111E806;
+    static const int GetDefaultTileSizeX2 = 0x1111E807;
+    static const int GetDefaultTileSizeY2 = 0x1111E808;
+    static const int GetTileProviders     = 0x1111E809;
 };
 /// \endcond
 

Modified: sandbox/jng/tiling/Common/MapGuideCommon/Services/TileService.h
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/Services/TileService.h	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Common/MapGuideCommon/Services/TileService.h	2014-05-30 15:31:40 UTC (rev 8177)
@@ -65,9 +65,9 @@
     /// image exists it will return it, otherwise the tile is rendered and added
     /// to the cache.
     ///
-    /// \param mapDefinition
+    /// \param resource
     /// Input
-    /// Resource identifier for the map definition
+    /// Resource identifier for the map definition or Tile Set Definition
     /// \param baseMapLayerGroupName
     /// Input
     /// Specifies the name of the baseMapLayerGroup for which to render the tile.
@@ -85,7 +85,7 @@
     /// A byte reader containing the rendered tile image.
     ///
     virtual MgByteReader* GetTile(
-        MgResourceIdentifier* mapDefinition,
+        MgResourceIdentifier* resource,
         CREFSTRING baseMapLayerGroupName,
         INT32 tileColumn,
         INT32 tileRow,
@@ -104,6 +104,18 @@
 
     //////////////////////////////////////////////////////////////////
     /// \brief
+    /// Clears the entire tile cache for the given tile set.  Tiles for all base
+    /// map layer groups and finite scales will be removed.
+    ///
+    /// \param map
+    /// Input
+    /// Specifies the map whose tile cache will be cleared.
+    ///
+    /// \since 3.0
+    virtual void ClearCache(MgResourceIdentifier* tileSet) = 0;
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
     /// Returns the default width of a tile.
     ///
     /// \return
@@ -122,6 +134,41 @@
     /// \since 1.2
     virtual INT32 GetDefaultTileSizeY() = 0;
 
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the default width of a tile.
+    ///
+    /// \param tileSet
+    /// Input
+    /// Specifies the resource id of the tile set
+    ///
+    /// \return
+    /// Default width of a tile in pixels.
+    ///
+    /// \since 3.0
+    virtual INT32 GetDefaultTileSizeX(MgResourceIdentifier* tileSet) = 0;
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the default height of a tile.
+    ///
+    /// \param tileSet
+    /// Input
+    /// Specifies the resource id of the tile set
+    ///
+    /// \return
+    /// Default height of a tile in pixels.
+    ///
+    /// \since 3.0
+    virtual INT32 GetDefaultTileSizeY(MgResourceIdentifier* tileSet) = 0;
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the list of available tile providers, along with supported connection parameters
+    ///
+    /// \since 3.0
+    virtual MgByteReader* GetTileProviders() = 0;
+
 INTERNAL_API:
 
     /////////////////////////////////////////////////////////////////

Modified: sandbox/jng/tiling/Common/PlatformBase/MapLayer/LayerGroup.cpp
===================================================================
--- sandbox/jng/tiling/Common/PlatformBase/MapLayer/LayerGroup.cpp	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Common/PlatformBase/MapLayer/LayerGroup.cpp	2014-05-30 15:31:40 UTC (rev 8177)
@@ -257,7 +257,7 @@
     stream->WriteBoolean(m_displayInLegend);
     stream->WriteBoolean(m_expandInLegend);
     stream->WriteString(m_legendLabel);
-    stream->WriteObject(m_tileSetId);
+    stream->WriteObject((MgResourceIdentifier*)m_tileSetId);
 }
 
 

Modified: sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.cpp
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.cpp	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.cpp	2014-05-30 15:31:40 UTC (rev 8177)
@@ -20,269 +20,26 @@
 
 IMPLEMENT_CREATE_SERVICE(MgServerTileService)
 
-ACE_Recursive_Thread_Mutex MgServerTileService::sm_mutex;
-bool MgServerTileService::sm_initialized = false;
-MgServerTileService::MapCache MgServerTileService::sm_mapCache;
-bool MgServerTileService::sm_renderOnly = false;
-INT32 MgServerTileService::sm_creationCutoffTime = 120;     // in seconds
-INT32 MgServerTileService::sm_pollingInterval = 1;          // in seconds
-INT32 MgServerTileService::sm_mapCacheSize = 10;
-
 MgServerTileService::MgServerTileService() : MgTileService()
 {
-    if (!sm_initialized)
-    {
-        // Perform Double-Checked Locking Optimization.
-        ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
-
-        if (!sm_initialized)
-        {
-            MgConfiguration* configuration = MgConfiguration::GetInstance();
-
-            configuration->GetBoolValue(
-                MgConfigProperties::TileServicePropertiesSection,
-                MgConfigProperties::TileServicePropertyRenderOnly,
-                sm_renderOnly,
-                MgConfigProperties::DefaultTileServicePropertyRenderOnly);
-
-            configuration->GetIntValue(
-                MgConfigProperties::TileServicePropertiesSection,
-                MgConfigProperties::TileServicePropertyCreationCutoffTime,
-                sm_creationCutoffTime,
-                MgConfigProperties::DefaultTileServicePropertyCreationCutoffTime);
-
-            configuration->GetIntValue(
-                MgConfigProperties::TileServicePropertiesSection,
-                MgConfigProperties::TileServicePropertyPollingInterval,
-                sm_pollingInterval,
-                MgConfigProperties::DefaultTileServicePropertyPollingInterval);
-
-            configuration->GetIntValue(
-                MgConfigProperties::TileServicePropertiesSection,
-                MgConfigProperties::TileServicePropertyTiledMapCacheSize,
-                sm_mapCacheSize,
-                MgConfigProperties::DefaultTileServicePropertyTiledMapCacheSize);
-
-            MgTileCache::Initialize();
-            sm_initialized = true;
-        }
-    }
-
-    m_tileCache = new MgTileCache();
+    MgTileCacheDefault::Initialize();
 }
 
-
 MgServerTileService::~MgServerTileService()
 {
-}
 
-///////////////////////////////////////////////////////////////////////////////
-/// \brief
-/// Determine if the tile cache is empty.
-///
-bool MgServerTileService::IsTileCacheEmpty() const
-{
-    ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, false));
-
-    return sm_mapCache.empty();
 }
 
-///////////////////////////////////////////////////////////////////////////////
-/// \brief
-/// Detect if the tile file has been locked by another thread or process.
-///
-bool MgServerTileService::DetectTileLockFile(CREFSTRING lockPathname)
+MgByteReader* MgServerTileService::GetTile(
+    MgMap* map,
+    CREFSTRING baseMapLayerGroupName,
+    INT32 tileColumn,
+    INT32 tileRow)
 {
-    bool found = false;
-    struct _stat64 lockFileInfo;
-
-    // Check the lock file to see if another thread/process is writing the tile file.
-    while (MgFileUtil::GetFileStatus(lockPathname, lockFileInfo))
-    {
-        time_t currTime;
-        ACE_OS::time(&currTime);
-        INT32 diffTime = (INT32)(currTime - lockFileInfo.st_mtime);
-
-        if (diffTime < sm_creationCutoffTime)
-        {
-            ACE_OS::sleep(sm_pollingInterval);
-        }
-        else
-        {
-            found = true;
-            break;
-        }
-    }
-
-    return found;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Create tilename from mapDefinition, scaleIndex, row, and column.
-// Remove lockfile, look for the tile in the cache, if not in cache create
-// lockfile and look for map in mapcache.
-MgByteReader* MgServerTileService::GetTile(MgResourceIdentifier* mapDefinition,
-                                           CREFSTRING baseMapLayerGroupName,
-                                           INT32 tileColumn,
-                                           INT32 tileRow,
-                                           INT32 scaleIndex)
-{
     Ptr<MgByteReader> ret;
-    FILE* lockFile = NULL;
-    STRING tilePathname, lockPathname;
 
     MG_TRY()
 
-    if (NULL == mapDefinition || baseMapLayerGroupName.empty())
-    {
-        throw new MgNullArgumentException(L"MgServerTileService.GetTile",
-            __LINE__, __WFILE__, NULL, L"", NULL);
-    }
-
-    if (scaleIndex < 0)
-    {
-        STRING buffer;
-        MgUtil::Int32ToString(scaleIndex, buffer);
-
-        MgStringCollection arguments;
-        arguments.Add(L"5");
-        arguments.Add(buffer);
-
-        throw new MgInvalidArgumentException(L"MgServerTileService.GetTile",
-            __LINE__, __WFILE__, &arguments, L"MgInvalidScaleIndex", NULL);
-    }
-
-    // get the service from our helper method
-    Ptr<MgResourceService> resourceService = GetResourceServiceForMapDef(mapDefinition,
-                                            L"MgServerTileService.GetTile");
-    // Generate tile and lock pathnames.
-    m_tileCache->GeneratePathnames(mapDefinition, scaleIndex, baseMapLayerGroupName,
-        tileColumn, tileRow, tilePathname, lockPathname, false);
-
-    // If there is a dangling lock file, then attempt to remove it.
-    if (DetectTileLockFile(lockPathname))
-    {
-        // TODO: Handle the exception by displaying a tile with an error message?
-        MgFileUtil::DeleteFile(lockPathname, true);
-    }
-
-    // try getting the tile from the cache
-    ret = m_tileCache->Get(tilePathname);
-
-    // if the reader is NULL then the tile wasn't in the cache and we
-    // need to generate it
-    while (NULL == ret)
-    {
-        // Attempt use a cached & serialized MgMap object
-        Ptr<MgMemoryStreamHelper> cachedMap;
-        STRING mapString = mapDefinition->ToString();
-        Ptr<MgMap> map;
-
-        // Protect the serialized MgMap cache with a mutex.  Stream reading is not
-        // thread safe so we need to deserialize the map within the mutex to ensure
-        // that a Rewind() is not called in the middle of a Deserialize().
-        // Lockfile test and creation is in same protected scope.
-        {
-            // Attempt to lock the tile file.
-            ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, NULL));
-
-            // Bail out if the tile file has been locked for so long.
-            if (DetectTileLockFile(lockPathname))
-            {
-                MgStringCollection arguments;
-                arguments.Add(lockPathname);
-
-                throw new MgFileIoException(L"MgServerTileService.GetTile",
-                    __LINE__, __WFILE__, &arguments, L"MgUnableToLockTileFile", NULL);
-            }
-
-            // try getting the tile from the cache
-            ret = m_tileCache->Get(tilePathname);
-
-            if (NULL != ret)
-            {
-                break;  // tile was in tileCache .. done.
-            }
-
-            // Create the lock file and close it right away.
-            m_tileCache->CreateFullPath(mapDefinition, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
-            lockFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(lockPathname), ACE_TEXT("wb"));
-
-            if (NULL == lockFile)
-            {
-                MgStringCollection arguments;
-                arguments.Add(lockPathname);
-
-                throw new MgFileIoException(L"MgServerTileService.GetTile",
-                    __LINE__, __WFILE__, &arguments, L"MgUnableToOpenLockFile", NULL);
-            }
-            else
-            {
-                ACE_OS::fclose(lockFile);
-            }
-
-            MapCache::const_iterator iter = sm_mapCache.find(mapString);
-            if (sm_mapCache.end() != iter)
-            {
-                cachedMap = SAFE_ADDREF((*iter).second);
-                cachedMap->Rewind();
-                Ptr<MgStream> stream = new MgStream(cachedMap);
-                map = new MgMap();
-                map->Deserialize(stream);
-            }
-            else
-            {
-                Ptr<MgSiteConnection> siteConn = new MgSiteConnection();
-                Ptr<MgUserInformation> userInfo = MgUserInformation::GetCurrentUserInfo();
-                siteConn->Open(userInfo);
-                map = new MgMap(siteConn);
-                map->Create(resourceService, mapDefinition, mapString);
-                cachedMap = new MgMemoryStreamHelper();
-                Ptr<MgStream> stream = new MgStream(cachedMap);
-                map->Serialize(stream);
-                if ((INT32)sm_mapCache.size() >= sm_mapCacheSize)
-                {
-                    ClearMapCache(L"");
-                }
-                sm_mapCache[mapString] = SAFE_ADDREF((MgMemoryStreamHelper*)cachedMap);
-            }
-        }   // end of mutex scope
-
-        double scale = map->GetFiniteDisplayScaleAt(scaleIndex);
-        map->SetViewScale(scale);
-
-        // Render the tile and cache it.
-        ret = GetTile(tilePathname, map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
-        break;
-    }
-
-    MG_CATCH(L"MgServerTileService.GetTile")
-
-    if (NULL != lockFile)
-    {
-        MgFileUtil::DeleteFile(lockPathname, false);
-    }
-
-    MG_THROW()
-
-    return ret.Detach();
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// look for the tile in the tilecache first
-MgByteReader* MgServerTileService::GetTile(MgMap* map,
-                                           CREFSTRING baseMapLayerGroupName,
-                                           INT32 tileColumn,
-                                           INT32 tileRow)
-{
-    Ptr<MgByteReader> ret;
-    FILE* lockFile = NULL;
-    STRING tilePathname, lockPathname;
-
-    MG_TRY()
-
     if (NULL == map || baseMapLayerGroupName.empty())
     {
         throw new MgNullArgumentException(L"MgServerTileService.GetTile",
@@ -300,240 +57,151 @@
             __LINE__, __WFILE__, NULL, L"", NULL);
     }
 
-    // Detect the lock file to see if another thread is creating the tile file.
-    m_tileCache->GeneratePathnames(map, scaleIndex, baseMapLayerGroupName,
-        tileColumn, tileRow, tilePathname, lockPathname, false);
+    Ptr<MgTileCacheDefault> cache = new MgTileCacheDefault(map);
+    ret = cache->GetTile(baseMapLayerGroupName, tileColumn, tileRow, scaleIndex);
 
-    // If there is a dangling lock file, then attempt to remove it.
-    if (DetectTileLockFile(lockPathname))
-    {
-        // TODO: Handle the exception by displaying a tile with an error message?
-        MgFileUtil::DeleteFile(lockPathname, true);
-    }
+    MG_CATCH_AND_THROW(L"MgServerTileService.GetTile")
 
-    // try getting the tile from the cache
-    ret = m_tileCache->Get(tilePathname);
+    return ret.Detach();
+}
 
-    // if the reader is NULL then the tile wasn't in the cache and we
-    // need to generate it
-    while (NULL == ret)
-    {
-        {
-            // Attemp to lock the tile file.
-            ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, NULL));
+MgByteReader* MgServerTileService::GetTile(
+    MgResourceIdentifier* resource,
+    CREFSTRING baseMapLayerGroupName,
+    INT32 tileColumn,
+    INT32 tileRow,
+    INT32 scaleIndex)
+{
+    Ptr<MgByteReader> ret;
 
-            // Bail out if the tile file has been locked for so long.
-            if (DetectTileLockFile(lockPathname))
-            {
-                MgStringCollection arguments;
-                arguments.Add(lockPathname);
+    MG_TRY()
 
-                throw new MgFileIoException(L"MgServerTileService.GetTile",
-                    __LINE__, __WFILE__, &arguments, L"MgUnableToLockTileFile", NULL);
-            }
-
-            // try getting the tile from the cache
-            ret = m_tileCache->Get(tilePathname);
-
-            if (NULL != ret)
-            {
-                break;
-            }
-
-            // Create the lock file and close it right away.
-            m_tileCache->CreateFullPath(map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
-            lockFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(lockPathname), ACE_TEXT("wb"));
-
-            if (NULL == lockFile)
-            {
-                MgStringCollection arguments;
-                arguments.Add(lockPathname);
-
-                throw new MgFileIoException(L"MgServerTileService.GetTile",
-                    __LINE__, __WFILE__, &arguments, L"MgUnableToOpenLockFile", NULL);
-            }
-            else
-            {
-                ACE_OS::fclose(lockFile);
-            }
-        }
-
-        // Render the tile and cache it.
-        ret = GetTile(tilePathname, map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
-        break;
-    }
-
-    MG_CATCH(L"MgServerTileService.GetTile")
-
-    if (NULL != lockFile)
+    if (NULL == resource || baseMapLayerGroupName.empty())
     {
-        MgFileUtil::DeleteFile(lockPathname, false);
+        throw new MgNullArgumentException(L"MgServerTileService.GetTile",
+            __LINE__, __WFILE__, NULL, L"", NULL);
     }
+        
+    Ptr<MgTileCache> cache = GetTileCache(resource);
+    ret = cache->GetTile(baseMapLayerGroupName, tileColumn, tileRow, scaleIndex);
 
-    MG_THROW()
+    MG_CATCH_AND_THROW(L"MgServerTileService.GetTile")
 
     return ret.Detach();
 }
 
-
-///////////////////////////////////////////////////////////////////////////////
-// render a tile and store it in the cache
-MgByteReader* MgServerTileService::GetTile(CREFSTRING tilePathname, MgMap* map, INT32 scaleIndex,
-    CREFSTRING baseMapLayerGroupName, INT32 tileColumn, INT32 tileRow)
+void MgServerTileService::ClearCache(MgMap* map)
 {
-    Ptr<MgByteReader> img;
+    MG_TRY()
 
-    // get a rendering service instance
-    MgServiceManager* serviceMan = MgServiceManager::GetInstance();
-    assert(NULL != serviceMan);
-    Ptr<MgRenderingService> svcRendering = dynamic_cast<MgRenderingService*>(
-        serviceMan->RequestService(MgServiceType::RenderingService));
-    assert(NULL != svcRendering);
+    CHECKARGUMENTNULL(map, L"MgServerTileService.ClearCache");
 
-    if (svcRendering != NULL)
-    {
-        // generate the tile
-        img = svcRendering->RenderTile(map, baseMapLayerGroupName, tileColumn, tileRow);
+    Ptr<MgTileCacheDefault> cache = new MgTileCacheDefault(map);
+    cache->Clear();
 
-        // cache the tile
-        if (!sm_renderOnly)
-        {
-            m_tileCache->Set(img, tilePathname);
-
-            // rewind the reader since setting the tile advances it to the end
-            if (img)
-            {
-                img->Rewind();
-            }
-        }
-    }
-
-    return img.Detach();
+    MG_CATCH_AND_THROW(L"MgServerTileService.ClearCache")
 }
 
-
-///////////////////////////////////////////////////////////////////////////////
-// take a tile image and store it in the tilecache using lockfiles
-void MgServerTileService::SetTile(MgByteReader* img,
-                                  MgMap* map,
-                                  INT32 scaleIndex,
-                                  CREFSTRING baseMapLayerGroupName,
-                                  INT32 tileColumn,
-                                  INT32 tileRow)
+void MgServerTileService::ClearCache(MgResourceIdentifier* tileSet)
 {
-    FILE* lockFile = NULL;
-    STRING tilePathname, lockPathname;
-
     MG_TRY()
 
-    if (NULL == img || NULL == map || baseMapLayerGroupName.empty())
-    {
-        throw new MgNullArgumentException(L"MgServerTileService.SetTile",
-            __LINE__, __WFILE__, NULL, L"", NULL);
-    }
+    CHECKARGUMENTNULL(tileSet, L"MgServerTileService.ClearCache");
 
-    if (scaleIndex < 0)
-    {
-        STRING buffer;
-        MgUtil::Int32ToString(scaleIndex, buffer);
+    Ptr<MgTileCache> cache = GetTileCache(tileSet);
+    cache->Clear();
 
-        MgStringCollection arguments;
-        arguments.Add(L"3");
-        arguments.Add(buffer);
+    MG_CATCH_AND_THROW(L"MgServerTileService.ClearCache")
+}
 
-        throw new MgInvalidArgumentException(L"MgServerTileService.GetTile",
-            __LINE__, __WFILE__, &arguments, L"MgInvalidScaleIndex", NULL);
-    }
+INT32 MgServerTileService::GetDefaultTileSizeX()
+{
+    return MgTileParameters::tileWidth;
+}
 
-    // Generate tile and lock pathnames.
-    m_tileCache->GeneratePathnames(map, scaleIndex, baseMapLayerGroupName,
-        tileColumn, tileRow, tilePathname, lockPathname, true);
+INT32 MgServerTileService::GetDefaultTileSizeY()
+{
+    return MgTileParameters::tileHeight;
+}
 
-    {
-        // Attemp to lock the tile file.
-        ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
+INT32 MgServerTileService::GetDefaultTileSizeX(MgResourceIdentifier* tileSet)
+{
+    INT32 ret = 0;
 
-        if (DetectTileLockFile(lockPathname))
-        {
-            // Attemp to remove a dangling lock file.
-            MgFileUtil::DeleteFile(lockPathname, true);
-        }
+    MG_TRY()
 
-        // Create the lock file and close it right away.
-        lockFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(lockPathname), ACE_TEXT("wb"));
+    Ptr<MgTileCache> cache = GetTileCache(tileSet);
+    ret = cache->GetDefaultTileSizeX();
 
-        if (NULL == lockFile)
-        {
-            MgStringCollection arguments;
-            arguments.Add(lockPathname);
+    MG_CATCH_AND_THROW(L"MgServerTileService.GetDefaultTileSizeX")
+    
+    return ret;
+}
 
-            throw new MgFileIoException(L"MgServerTileService.SetTile",
-                __LINE__, __WFILE__, &arguments, L"MgUnableToOpenLockFile", NULL);
-        }
-        else
-        {
-            ACE_OS::fclose(lockFile);
-        }
-    }
+INT32 MgServerTileService::GetDefaultTileSizeY(MgResourceIdentifier* tileSet)
+{
+    INT32 ret = 0;
 
-    // cache the tile
-    m_tileCache->Set(img, tilePathname);
+    MG_TRY()
 
-    MG_CATCH(L"MgServerTileService.SetTile")
+    Ptr<MgTileCache> cache = GetTileCache(tileSet);
+    ret = cache->GetDefaultTileSizeX();
 
-    if (NULL != lockFile)
-    {
-        MgFileUtil::DeleteFile(lockPathname, false);
-    }
+    MG_CATCH_AND_THROW(L"MgServerTileService.GetDefaultTileSizeY")
 
-    MG_THROW()
+    return ret;
 }
 
-
-///////////////////////////////////////////////////////////////////////////////
-// accessor method for resource service
-MgResourceService* MgServerTileService::GetResourceServiceForMapDef(MgResourceIdentifier* mapDefinition,
-                                                                    CREFSTRING funcName)
+MgByteReader* MgServerTileService::GetTileProviders()
 {
-    // get service manager
-    MgServiceManager* serviceMan = MgServiceManager::GetInstance();
-    assert(NULL != serviceMan);
+    Ptr<MgByteReader> ret;
 
-    // Get the service from service manager
-    Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>(
-        serviceMan->RequestService(MgServiceType::ResourceService));
-    assert(NULL != resourceService);
+    MG_TRY()
+    MG_CATCH_AND_THROW(L"MgServerTileService.GetTileProviders")
 
-    if (!resourceService->HasPermission(mapDefinition, MgResourcePermission::ReadOnly))
-    {
-        MG_LOG_AUTHENTICATION_ENTRY(MgResources::PermissionDenied.c_str());
+    return ret.Detach();
+}
 
-        MgStringCollection arguments;
-        arguments.Add(mapDefinition->ToString());
+void MgServerTileService::SetTile(
+    MgByteReader* img,
+    MgMap* map,
+    INT32 scaleIndex,
+    CREFSTRING baseMapLayerGroupName,
+    INT32 tileColumn,
+    INT32 tileRow)
+{
+    MG_TRY()
 
-        throw new MgPermissionDeniedException(
-            funcName, __LINE__, __WFILE__, &arguments, L"", NULL);
-    }
-    return resourceService.Detach();
+    Ptr<MgTileCacheDefault> cache = new MgTileCacheDefault(map);
+    cache->SetTile(baseMapLayerGroupName, tileColumn, tileRow, scaleIndex, img);
+
+    MG_CATCH_AND_THROW(L"MgServerTileService.SetTile")
 }
 
-
-///////////////////////////////////////////////////////////////////////////////
-void MgServerTileService::ClearCache(MgMap* map)
+MgTileCache* MgServerTileService::GetTileCache(MgResourceIdentifier* resource)
 {
+    Ptr<MgTileCache> cache;
+
     MG_TRY()
 
-    if (NULL == map)
-        throw new MgNullArgumentException(L"MgServerTileService.ClearCache", __LINE__, __WFILE__, NULL, L"", NULL);
+    if (resource->GetResourceType() == MgResourceType::MapDefinition)
+    {
+        cache = new MgTileCacheDefault(resource);
+    }
+    else if (resource->GetResourceType() == MgResourceType::TileSetDefinition)
+    {
 
-    Ptr<MgResourceIdentifier> resourceId = map->GetMapDefinition();
-    ClearMapCache(resourceId->ToString());
+    }
 
-    m_tileCache->Clear(map);
+    MG_CATCH_AND_THROW(L"MgServerTileService.GetTileCache")
 
-    MG_CATCH_AND_THROW(L"MgServerTileService.ClearCache")
+    return cache.Detach();
 }
 
+bool MgServerTileService::IsTileCacheEmpty() const
+{
+    return false;
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 /// \brief
@@ -562,12 +230,17 @@
                 {
                     MG_TRY()
 
-                    // clear any cached mgmap objects
-                    ClearMapCache(resource->ToString());
-
                     // clear any tile cache associated with this map
-                    m_tileCache->Clear(resource);
+                    Ptr<MgTileCache> cache = GetTileCache(resource);
+                    cache->Clear();
 
+                    MgTileCacheDefault* cacheDefault = dynamic_cast<MgTileCacheDefault*>(cache.p);
+                    if (NULL != cacheDefault)
+                    {
+                        // clear any cached mgmap objects
+                        cacheDefault->ClearMapCache(resource->ToString());
+                    }
+
                     MG_CATCH(L"MgServerTileService.NotifyResourcesChanged")
 
                     if (NULL != mgException.p)
@@ -593,61 +266,8 @@
     return success;
 }
 
-
 ///////////////////////////////////////////////////////////////////////////////
 void MgServerTileService::SetConnectionProperties(MgConnectionProperties*)
 {
     // Do nothing.  No connection properties are required for Server-side service objects.
 }
-
-
-///////////////////////////////////////////////////////////////////////////////
-void MgServerTileService::ClearMapCache(CREFSTRING mapDefinition)
-{
-    ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
-    MapCache::iterator iter = sm_mapCache.end();
-    if (mapDefinition.empty())
-    {
-        for (iter = sm_mapCache.begin(); iter != sm_mapCache.end(); ++iter)
-        {
-            SAFE_RELEASE((*iter).second);
-            (*iter).second = NULL;
-        }
-        sm_mapCache.clear();
-
-        STRING message;
-        MgResources* resources = NULL;
-        MG_TRY()
-        resources = MgResources::GetInstance();
-        if (NULL != resources)
-        {
-            message = resources->GetResourceMessage(MgResources::ErrorDescription, L"MgMapCacheCleared", NULL);
-            MG_LOG_ERROR_ENTRY(message.c_str());
-        }
-        MG_CATCH_AND_RELEASE()
-    }
-    else
-    {
-        iter = sm_mapCache.find(mapDefinition);
-        if (sm_mapCache.end() != iter)
-        {
-            SAFE_RELEASE((*iter).second);
-            (*iter).second = NULL;
-            sm_mapCache.erase(iter);
-        }
-    }
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-INT32 MgServerTileService::GetDefaultTileSizeX()
-{
-    return MgTileParameters::tileWidth;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-INT32 MgServerTileService::GetDefaultTileSizeY()
-{
-    return MgTileParameters::tileHeight;
-}

Modified: sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.h
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.h	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.h	2014-05-30 15:31:40 UTC (rev 8177)
@@ -24,65 +24,54 @@
 class MG_SERVER_TILE_API MgServerTileService : public MgTileService
 {
     DECLARE_CLASSNAME(MgServerTileService)
-
 public:
     MgServerTileService();
     ~MgServerTileService();
     DECLARE_CREATE_SERVICE()
 
-    virtual MgByteReader* GetTile(MgMap* map,
-                                  CREFSTRING baseMapLayerGroupName,
-                                  INT32 tileColumn,
-                                  INT32 tileRow);
+    virtual MgByteReader* GetTile(
+        MgMap* map,
+        CREFSTRING baseMapLayerGroupName,
+        INT32 tileColumn,
+        INT32 tileRow);
 
-    virtual MgByteReader* GetTile(MgResourceIdentifier* mapDefinition,
-                                  CREFSTRING baseMapLayerGroupName,
-                                  INT32 tileColumn,
-                                  INT32 tileRow,
-                                  INT32 scaleIndex);
+    virtual MgByteReader* GetTile(
+        MgResourceIdentifier* resource,
+        CREFSTRING baseMapLayerGroupName,
+        INT32 tileColumn,
+        INT32 tileRow,
+        INT32 scaleIndex);
 
-    virtual void SetTile(MgByteReader* img,
-                         MgMap* map,
-                         INT32 scaleIndex,
-                         CREFSTRING baseMapLayerGroupName,
-                         INT32 tileColumn,
-                         INT32 tileRow);
-
     virtual void ClearCache(MgMap* map);
 
+    virtual void ClearCache(MgResourceIdentifier* tileSet);
+
     virtual INT32 GetDefaultTileSizeX();
 
     virtual INT32 GetDefaultTileSizeY();
 
-    virtual bool IsTileCacheEmpty() const;
-    virtual bool NotifyResourcesChanged(MgSerializableCollection* resources,
-        bool strict = true);
+    virtual INT32 GetDefaultTileSizeX(MgResourceIdentifier* tileSet);
 
-    void SetConnectionProperties(MgConnectionProperties* connProp);
+    virtual INT32 GetDefaultTileSizeY(MgResourceIdentifier* tileSet);
 
-private:
+    virtual MgByteReader* GetTileProviders();
 
-    bool DetectTileLockFile(CREFSTRING lockPathname);
+    virtual void SetTile(
+        MgByteReader* img,
+        MgMap* map,
+        INT32 scaleIndex,
+        CREFSTRING baseMapLayerGroupName,
+        INT32 tileColumn,
+        INT32 tileRow);
 
-    MgByteReader* GetTile(CREFSTRING tilePathname, MgMap* map, INT32 scaleIndex,
-        CREFSTRING baseMapLayerGroupName, INT32 tileColumn, INT32 tileRow);
+    virtual bool IsTileCacheEmpty() const;
 
-    void ClearMapCache(CREFSTRING mapName);
+    virtual bool NotifyResourcesChanged(MgSerializableCollection* resources, bool strict = true);
 
-    MgResourceService* GetResourceServiceForMapDef(MgResourceIdentifier* mapDefinition, CREFSTRING funcName);
+    void SetConnectionProperties(MgConnectionProperties* connProp);
 
-    // member data
-    Ptr<MgTileCache> m_tileCache;
-
-    typedef std::map<STRING, MgMemoryStreamHelper*> MapCache;
-
-    static ACE_Recursive_Thread_Mutex sm_mutex;
-    static bool sm_initialized;
-    static MapCache sm_mapCache;
-    static bool sm_renderOnly;
-    static INT32 sm_creationCutoffTime;
-    static INT32 sm_pollingInterval;
-    static INT32 sm_mapCacheSize;
+private:
+    MgTileCache* GetTileCache(MgResourceIdentifier* resource);
 };
 
 #endif

Modified: sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj	2014-05-30 15:31:40 UTC (rev 8177)
@@ -228,6 +228,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="TileCacheDefault.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="TileOperation.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -272,6 +278,7 @@
     <ClInclude Include="OpGetDefaultTileSizeY.h" />
     <ClInclude Include="OpGetTile.h" />
     <ClInclude Include="OpSetTile.h" />
+    <ClInclude Include="TileCacheDefault.h" />
     <ClInclude Include="TileOperation.h" />
     <ClInclude Include="TileOperationFactory.h" />
     <ClInclude Include="ServerTileDllExport.h" />

Modified: sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj.filters
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj.filters	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj.filters	2014-05-30 15:31:40 UTC (rev 8177)
@@ -32,6 +32,7 @@
     <ClCompile Include="ServerTileServiceBuild.cpp" />
     <ClCompile Include="TileCache.cpp" />
     <ClCompile Include="TileServiceHandler.cpp" />
+    <ClCompile Include="TileCacheDefault.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="OpClearCache.h">
@@ -60,6 +61,7 @@
     <ClInclude Include="..\..\Common\stdafx.h" />
     <ClInclude Include="TileCache.h" />
     <ClInclude Include="TileServiceHandler.h" />
+    <ClInclude Include="TileCacheDefault.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ServerTileService.rc" />

Modified: sandbox/jng/tiling/Server/src/Services/Tile/ServerTileServiceBuild.cpp
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/ServerTileServiceBuild.cpp	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Server/src/Services/Tile/ServerTileServiceBuild.cpp	2014-05-30 15:31:40 UTC (rev 8177)
@@ -24,6 +24,7 @@
 #include "OpGetDefaultTileSizeX.cpp"
 #include "OpGetDefaultTileSizeY.cpp"
 #include "TileCache.cpp"
+#include "TileCacheDefault.cpp"
 #include "TileOperation.cpp"
 #include "TileOperationFactory.cpp"
 #include "TileServiceHandler.cpp"

Modified: sandbox/jng/tiling/Server/src/Services/Tile/TileCache.cpp
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/TileCache.cpp	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Server/src/Services/Tile/TileCache.cpp	2014-05-30 15:31:40 UTC (rev 8177)
@@ -18,406 +18,12 @@
 #include "MapGuideCommon.h"
 #include "TileCache.h"
 
-const STRING SCALE_INDEX_PREFIX = L"S";
-const STRING ROW_PREFIX = L"R";
-const STRING COLUMN_PREFIX = L"C";
-
-STRING MgTileCache::sm_path = L"";
-INT32 MgTileCache::sm_tileColumnsPerFolder = 30;
-INT32 MgTileCache::sm_tileRowsPerFolder = 30;
-
-// default constructor
 MgTileCache::MgTileCache()
 {
-}
 
-///////////////////////////////////////////////////////////////////////////////
-/// \brief
-/// Initialize the tile cache configuration.
-///
-void MgTileCache::Initialize()
-{
-    if (sm_path.empty())
-    {
-        // initialize the tile cache path
-        MgConfiguration* configuration = MgConfiguration::GetInstance();
-
-        configuration->GetStringValue(
-            MgConfigProperties::TileServicePropertiesSection,
-            MgConfigProperties::TileServicePropertyTileCachePath,
-            sm_path,
-            MgConfigProperties::DefaultTileServicePropertyTileCachePath);
-
-        // generate directory location for tile cache
-        MgFileUtil::AppendSlashToEndOfPath(sm_path);
-
-        // create directory if it is not already there
-        MgFileUtil::CreateDirectory(sm_path, false, true);
-
-        configuration->GetIntValue(MgConfigProperties::TileServicePropertiesSection,
-            MgConfigProperties::TileServicePropertyTileColumnsPerFolder,
-            sm_tileColumnsPerFolder,
-            MgConfigProperties::DefaultTileServicePropertyTileColumnsPerFolder);
-
-        configuration->GetIntValue(MgConfigProperties::TileServicePropertiesSection,
-            MgConfigProperties::TileServicePropertyTileRowsPerFolder,
-            sm_tileRowsPerFolder,
-            MgConfigProperties::DefaultTileServicePropertyTileRowsPerFolder);
-
-        configuration->GetIntValue(MgConfigProperties::TileServicePropertiesSection,
-            MgConfigProperties::TileServicePropertyTileSizeX,
-            MgTileParameters::tileWidth,
-            MgConfigProperties::DefaultTileServicePropertyTileSizeX);
-
-        configuration->GetIntValue(MgConfigProperties::TileServicePropertiesSection,
-            MgConfigProperties::TileServicePropertyTileSizeY,
-            MgTileParameters::tileHeight,
-            MgConfigProperties::DefaultTileServicePropertyTileSizeY);
-
-        STRING format;
-        configuration->GetStringValue(MgConfigProperties::TileServicePropertiesSection,
-            MgConfigProperties::TileServicePropertyImageFormat,
-            format,
-            MgConfigProperties::DefaultTileServicePropertyImageFormat);
-
-        // Only allow GIF, PNG, PNG8 and JPG as tile formats
-        if (format == MgImageFormats::Png || format == MgImageFormats::Png8 || format == MgImageFormats::Jpeg || format == MgImageFormats::Gif)
-        {
-            MgTileParameters::tileFormat = format;
-        }
-        else
-        {
-            MgTileParameters::tileFormat = MgImageFormats::Png;
-        }
-    }
 }
 
-///////////////////////////////////////////////////////////////////////////////
-/// \brief
-/// Generate tile and lock pathnames.
-///
-void MgTileCache::GeneratePathnames(MgResourceIdentifier* mapDef, int scaleIndex,
-    CREFSTRING group, int tileColumn, int tileRow,
-    STRING& tilePathname, STRING& lockPathname, bool createFullPath)
+MgTileCache::~MgTileCache()
 {
-    STRING fileName = L"/" + GetTileName(tileRow, tileColumn) + L".";
-    STRING basePath = GetBasePath(mapDef);
 
-    if (createFullPath)
-    {
-        tilePathname = CreateFullPath(basePath, scaleIndex, group, tileColumn, tileRow);
-    }
-    else
-    {
-        tilePathname = GetFullPath(basePath, scaleIndex, group, tileColumn, tileRow);
-    }
-
-    // Generate the tile and lock pathnames
-    //     <tilePathname> = <fullPath>/<row>_<column>.png/jpg
-    //     <lockPathname> = <fullPath>/<row>_<column>.lck
-    tilePathname += fileName;
-    lockPathname = tilePathname;
-    if (MgTileParameters::tileFormat == MgImageFormats::Jpeg)
-    {
-        tilePathname += L"jpg";
-    }
-    else if (MgTileParameters::tileFormat == MgImageFormats::Gif)
-    {
-        tilePathname += L"gif";
-    }
-    else
-    {
-        tilePathname += L"png";
-    }
-
-    lockPathname += L"lck";
 }
-
-void MgTileCache::GeneratePathnames(MgMap* map, int scaleIndex,
-    CREFSTRING group, int tileColumn, int tileRow,
-    STRING& tilePathname, STRING& lockPathname, bool createFullPath)
-{
-    assert(NULL != map);
-    Ptr<MgResourceIdentifier> mapDef = map->GetMapDefinition();
-
-    GeneratePathnames(mapDef, scaleIndex, group, tileColumn, tileRow,
-        tilePathname, lockPathname, createFullPath);
-}
-
-// returns any cached tile for the given pathname
-MgByteReader* MgTileCache::Get(CREFSTRING tilePathname)
-{
-    Ptr<MgByteReader> ret;
-
-    MG_TRY()
-
-    if (MgFileUtil::PathnameExists(tilePathname))
-    {
-        Ptr<MgByteSource> byteSource = new MgByteSource(tilePathname, false);
-
-        if (MgTileParameters::tileFormat == MgImageFormats::Jpeg)
-        {
-            byteSource->SetMimeType(MgMimeType::Jpeg);
-        }
-        else if (MgTileParameters::tileFormat == MgImageFormats::Gif)
-        {
-            byteSource->SetMimeType(MgMimeType::Gif);
-        }
-        else
-        {
-            byteSource->SetMimeType(MgMimeType::Png);
-        }
-
-        ret = byteSource->GetReader();
-    }
-
-    MG_CATCH_AND_RELEASE()
-
-    return ret.Detach();
-}
-
-// caches a tile for the given pathname
-void MgTileCache::Set(MgByteReader* img, CREFSTRING tilePathname)
-{
-    if (img != NULL)
-    {
-        Ptr<MgByteSink> byteSink = new MgByteSink(img);
-
-        byteSink->ToFile(tilePathname);
-    }
-}
-
-// clears the tile cache for the given map
-void MgTileCache::Clear(MgMap* map)
-{
-    if (map != NULL)
-    {
-        STRING basePath = GetBasePath(map);
-
-        // delete main map directory
-        if (!basePath.empty())
-            MgFileUtil::DeleteDirectory(basePath, true, false);
-    }
-}
-
-// clears the tile cache for the given map
-void MgTileCache::Clear(MgResourceIdentifier* mapDef)
-{
-    // the resource must be a map definition
-    if (mapDef != NULL && mapDef->GetResourceType() == MgResourceType::MapDefinition)
-    {
-        STRING basePath = GetBasePath(mapDef);
-
-        // delete main map directory
-        if (!basePath.empty())
-            MgFileUtil::DeleteDirectory(basePath, true, false);
-    }
-}
-
-// gets the base path to use with the tile cache for the given map definition resource
-STRING MgTileCache::GetBasePath(MgResourceIdentifier* mapDef)
-{
-    assert(mapDef != NULL);
-    assert(mapDef->GetResourceType() == MgResourceType::MapDefinition);
-    STRING mapPath;
-
-    if (mapDef->GetRepositoryType() == MgRepositoryType::Library)
-    {
-        // for maps in the library repository the path+name is unique
-        mapPath  = mapDef->GetPath();
-        mapPath += L"_";
-        mapPath += mapDef->GetName();
-    }
-    else if (mapDef->GetRepositoryType() == MgRepositoryType::Session)
-    {
-        // for maps in the session repository we use the session + path + map name
-        mapPath  = mapDef->GetRepositoryName();
-        mapPath += L"_";
-
-        STRING resourcePath  = mapDef->GetPath();
-
-        if (!resourcePath.empty())
-        {
-            mapPath += resourcePath;
-            mapPath += L"_";
-        }
-
-        mapPath += mapDef->GetName();
-    }
-    else
-    {
-        // shouldn't get here
-        assert(false);
-        return mapPath;
-    }
-
-    // for safety
-    mapPath = MgUtil::ReplaceString(mapPath, L"/", L"_");
-    mapPath = MgUtil::ReplaceString(mapPath, L":", L"_");
-
-    // Build the base path using format "%ls%ls":
-    //     <basePath> = <tileCachePath><mapPath>
-    STRING basePath = sm_path;
-    basePath += mapPath;
-
-    return basePath;
-}
-
-// gets the base path to use with the tile cache for the given map
-STRING MgTileCache::GetBasePath(MgMap* map)
-{
-    assert(NULL != map);
-    Ptr<MgResourceIdentifier> mapDef = map->GetMapDefinition();
-    return GetBasePath(mapDef);
-}
-
-// gets the full path to use with the tile cache for the given base path / scale index / group
-STRING MgTileCache::GetFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
-{
-    // Build full path
-    //     <fullPath> = <basePath>/<scaleIndex>/<group>/<rowFolder>/<columnFolder>
-    assert(!basePath.empty());
-    STRING fullPath = basePath;
-
-    fullPath += L"/";
-    fullPath += GetScaleIndexFolder(scaleIndex);
-
-    fullPath += L"/";
-    fullPath += group;
-
-    fullPath += L"/";
-    fullPath += GetRowFolder(tileRow);
-
-    fullPath += L"/";
-    fullPath += GetColumnFolder(tileColumn);
-
-    return fullPath;
-}
-
-// gets the full path to use with the tile cache for the given map definition / scale index / group
-STRING MgTileCache::GetFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
-{
-    return GetFullPath(GetBasePath(mapDef), scaleIndex, group, tileColumn, tileRow);
-}
-
-// gets the full path to use with the tile cache for the given map / scale index / group
-STRING MgTileCache::GetFullPath(MgMap* map, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
-{
-    assert(NULL != map);
-    Ptr<MgResourceIdentifier> mapDef = map->GetMapDefinition();
-    return GetFullPath(mapDef, scaleIndex, group, tileColumn, tileRow);
-}
-
-STRING MgTileCache::CreateFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
-{
-    assert(!basePath.empty());
-    STRING fullPath = basePath;
-
-    // Create base directory if it does not exist.
-    MgFileUtil::CreateDirectory(fullPath, false);
-
-    // Create scale directory if it does not exist.
-    fullPath += L"/";
-    fullPath += GetScaleIndexFolder(scaleIndex);
-    MgFileUtil::CreateDirectory(fullPath, false);
-
-    // Create group directory if it does not exist.
-    fullPath += L"/";
-    fullPath += group;
-    MgFileUtil::CreateDirectory(fullPath, false);
-
-    // Create row directory if it does not exist.
-    fullPath += L"/";
-    fullPath += GetRowFolder(tileRow);
-    MgFileUtil::CreateDirectory(fullPath, false);
-
-    // Create column directory if it does not exist.
-    fullPath += L"/";
-    fullPath += GetColumnFolder(tileColumn);
-    MgFileUtil::CreateDirectory(fullPath, false);
-
-    return fullPath;
-}
-
-STRING MgTileCache::CreateFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
-{
-    return CreateFullPath(GetBasePath(mapDef), scaleIndex, group, tileColumn, tileRow);
-}
-
-STRING MgTileCache::CreateFullPath(MgMap* map, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
-{
-    return CreateFullPath(GetBasePath(map), scaleIndex, group, tileColumn, tileRow);
-}
-
-// Get the folder name corresponding to the specified scale index
-STRING MgTileCache::GetScaleIndexFolder(int scaleIndex)
-{
-    STRING scaleIndexString;
-    MgUtil::Int32ToString(scaleIndex, scaleIndexString);
-    return SCALE_INDEX_PREFIX + scaleIndexString;
-}
-
-// Get the folder name corresponding to the specified tile row
-STRING MgTileCache::GetRowFolder(int tileRow)
-{
-    return GetFolder(ROW_PREFIX, tileRow, sm_tileRowsPerFolder);
-}
-
-// Get the folder name corresponding to the specified tile column
-STRING MgTileCache::GetColumnFolder(int tileColumn)
-{
-    return GetFolder(COLUMN_PREFIX, tileColumn, sm_tileColumnsPerFolder);
-}
-
-// Get the parent folder for a given row or column
-STRING MgTileCache::GetFolder(STRING prefix, int tileIndex, int tilesPerFolder)
-{
-    STRING folder;
-
-    // Determine which folder contains this tile
-    int folderIndex = tileIndex / tilesPerFolder;
-    int firstTileIndex = folderIndex * tilesPerFolder;
-    if(tileIndex < 0 && firstTileIndex == 0)
-    {
-        folder = L"-0";
-    }
-    else
-    {
-        MgUtil::Int32ToString(firstTileIndex, folder);
-    }
-    return prefix + folder;
-}
-
-// Get the filename corresponding to the specified row and column.
-// No file extension is added.
-STRING MgTileCache::GetTileName(int tileRow, int tileColumn)
-{
-    return GetTileIndexString(tileRow, sm_tileRowsPerFolder) + L"_" +
-        GetTileIndexString(tileColumn, sm_tileColumnsPerFolder);
-}
-
-// When a tile is stored in a folder, the index value of the parent folder
-// is subtracted from the overall tile index.
-// e.g. If we store 30 rows of tiles per folder, a tile with overall row
-// index 73 will be stored in the row folder "R60" with a row index of 13.
-// Note: Negative values are maintained even near the origin, so a tile with
-// an overall row index of -13 would be stored in row folder "R-0" with a
-// row index of -13.
-STRING MgTileCache::GetTileIndexString(int tileIndex, int tilesPerFolder)
-{
-    STRING name;
-
-    // Determine the offset of this tile within the folder
-    int tileNameIndex = tileIndex % tilesPerFolder;
-    if(tileIndex < 0 && tileNameIndex == 0)
-    {
-        name = L"-0";
-    }
-    else
-    {
-        MgUtil::Int32ToString(tileNameIndex, name);
-    }
-    return name;
-}
-
-

Modified: sandbox/jng/tiling/Server/src/Services/Tile/TileCache.h
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/TileCache.h	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Server/src/Services/Tile/TileCache.h	2014-05-30 15:31:40 UTC (rev 8177)
@@ -20,61 +20,30 @@
 
 #include "ServerTileDllExport.h"
 
-// File-system-based cache for base map layer group tiles generated by the rendering service.
+//An abstract tile cache
 class MG_SERVER_TILE_API MgTileCache : public MgDisposable
 {
 public:
     MgTileCache();
+    virtual ~MgTileCache();
 
-    static void Initialize();
+    virtual MgByteReader* GetTile(CREFSTRING baseMapLayerGroupName,
+                                  INT32 tileColumn,
+                                  INT32 tileRow,
+                                  INT32 scaleIndex) = 0;
 
-    void GeneratePathnames(MgResourceIdentifier* mapDef, int scaleIndex,
-        CREFSTRING group, int tileColumn, int tileRow,
-        STRING& tilePathname, STRING& lockPathname, bool createFullPath);
-    void GeneratePathnames(MgMap* map, int scaleIndex,
-        CREFSTRING group, int tileColumn, int tileRow,
-        STRING& tilePathname, STRING& lockPathname, bool createFullPath);
+    
+    virtual void SetTile(CREFSTRING baseMapLayerGroupName,
+                         INT32 tileColumn,
+                         INT32 tileRow,
+                         INT32 scaleIndex,
+                         MgByteReader* img) = 0;
 
-    STRING CreateFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
-    STRING CreateFullPath(MgMap* map, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
+    virtual void Clear() = 0;
 
-    MgByteReader* Get(CREFSTRING tilePathname);
-    void Set(MgByteReader* img, CREFSTRING tilePathname);
+    virtual INT32 GetDefaultTileSizeX() = 0;
 
-    void Clear(MgMap* map);
-    void Clear(MgResourceIdentifier* mapDef);
-
-protected:
-    virtual void Dispose()
-    {
-        delete this;
-    }
-
-private:
-    // Unimplemented Constructors/Methods
-    MgTileCache(const MgTileCache&);
-    MgTileCache& operator=(const MgTileCache&);
-
-    STRING GetBasePath(MgResourceIdentifier* mapDef);
-    STRING GetBasePath(MgMap* map);
-
-    STRING GetFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
-    STRING GetFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
-    STRING GetFullPath(MgMap* map, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
-
-    STRING CreateFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
-
-    STRING GetScaleIndexFolder(int scaleIndex);
-    STRING GetRowFolder(int tileRow);
-    STRING GetColumnFolder(int tileColumn);
-    STRING GetFolder(STRING prefix, int tileIndex, int tilesPerFolder);
-
-    STRING GetTileName(int tileRow, int tileColumn);
-    STRING GetTileIndexString(int tileIndex, int tilesPerFolder);
-
-    static STRING sm_path;
-    static INT32 sm_tileColumnsPerFolder;
-    static INT32 sm_tileRowsPerFolder;
+    virtual INT32 GetDefaultTileSizeY() = 0;
 };
 
 #endif

Added: sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.cpp
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.cpp	                        (rev 0)
+++ sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.cpp	2014-05-30 15:31:40 UTC (rev 8177)
@@ -0,0 +1,943 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "MapGuideCommon.h"
+#include "TileCacheDefault.h"
+#include "ServiceManager.h"
+
+const STRING SCALE_INDEX_PREFIX = L"S";
+const STRING ROW_PREFIX = L"R";
+const STRING COLUMN_PREFIX = L"C";
+
+STRING MgTileCacheDefault::sm_path = L"";
+INT32 MgTileCacheDefault::sm_tileColumnsPerFolder = 30;
+INT32 MgTileCacheDefault::sm_tileRowsPerFolder = 30;
+
+ACE_Recursive_Thread_Mutex MgTileCacheDefault::sm_mutex;
+MgTileCacheDefault::MapCache MgTileCacheDefault::sm_mapCache;
+bool MgTileCacheDefault::sm_initialized = false;
+bool MgTileCacheDefault::sm_renderOnly = false;
+INT32 MgTileCacheDefault::sm_creationCutoffTime = 120;     // in seconds
+INT32 MgTileCacheDefault::sm_pollingInterval = 1;          // in seconds
+INT32 MgTileCacheDefault::sm_mapCacheSize = 10;
+
+MgTileCacheDefault::MgTileCacheDefault(MgMap* map)
+{
+    m_map = SAFE_ADDREF(map);
+    m_resourceId = NULL;
+}
+
+MgTileCacheDefault::MgTileCacheDefault(MgResourceIdentifier* resource)
+{
+    m_map = NULL;
+    m_resourceId = SAFE_ADDREF(resource);
+}
+
+MgTileCacheDefault::~MgTileCacheDefault()
+{
+
+}
+
+void MgTileCacheDefault::Initialize()
+{
+    if (!sm_initialized)
+    {
+        // Perform Double-Checked Locking Optimization.
+        ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
+
+        if (!sm_initialized)
+        {
+            MgConfiguration* configuration = MgConfiguration::GetInstance();
+
+            configuration->GetBoolValue(
+                MgConfigProperties::TileServicePropertiesSection,
+                MgConfigProperties::TileServicePropertyRenderOnly,
+                sm_renderOnly,
+                MgConfigProperties::DefaultTileServicePropertyRenderOnly);
+
+            configuration->GetIntValue(
+                MgConfigProperties::TileServicePropertiesSection,
+                MgConfigProperties::TileServicePropertyCreationCutoffTime,
+                sm_creationCutoffTime,
+                MgConfigProperties::DefaultTileServicePropertyCreationCutoffTime);
+
+            configuration->GetIntValue(
+                MgConfigProperties::TileServicePropertiesSection,
+                MgConfigProperties::TileServicePropertyPollingInterval,
+                sm_pollingInterval,
+                MgConfigProperties::DefaultTileServicePropertyPollingInterval);
+
+            configuration->GetIntValue(
+                MgConfigProperties::TileServicePropertiesSection,
+                MgConfigProperties::TileServicePropertyTiledMapCacheSize,
+                sm_mapCacheSize,
+                MgConfigProperties::DefaultTileServicePropertyTiledMapCacheSize);
+
+            if (sm_path.empty())
+            {
+                configuration->GetStringValue(
+                    MgConfigProperties::TileServicePropertiesSection,
+                    MgConfigProperties::TileServicePropertyTileCachePath,
+                    sm_path,
+                    MgConfigProperties::DefaultTileServicePropertyTileCachePath);
+
+                // generate directory location for tile cache
+                MgFileUtil::AppendSlashToEndOfPath(sm_path);
+
+                // create directory if it is not already there
+                MgFileUtil::CreateDirectory(sm_path, false, true);
+
+                configuration->GetIntValue(MgConfigProperties::TileServicePropertiesSection,
+                    MgConfigProperties::TileServicePropertyTileColumnsPerFolder,
+                    sm_tileColumnsPerFolder,
+                    MgConfigProperties::DefaultTileServicePropertyTileColumnsPerFolder);
+
+                configuration->GetIntValue(MgConfigProperties::TileServicePropertiesSection,
+                    MgConfigProperties::TileServicePropertyTileRowsPerFolder,
+                    sm_tileRowsPerFolder,
+                    MgConfigProperties::DefaultTileServicePropertyTileRowsPerFolder);
+
+                configuration->GetIntValue(MgConfigProperties::TileServicePropertiesSection,
+                    MgConfigProperties::TileServicePropertyTileSizeX,
+                    MgTileParameters::tileWidth,
+                    MgConfigProperties::DefaultTileServicePropertyTileSizeX);
+
+                configuration->GetIntValue(MgConfigProperties::TileServicePropertiesSection,
+                    MgConfigProperties::TileServicePropertyTileSizeY,
+                    MgTileParameters::tileHeight,
+                    MgConfigProperties::DefaultTileServicePropertyTileSizeY);
+
+                STRING format;
+                configuration->GetStringValue(MgConfigProperties::TileServicePropertiesSection,
+                    MgConfigProperties::TileServicePropertyImageFormat,
+                    format,
+                    MgConfigProperties::DefaultTileServicePropertyImageFormat);
+
+                // Only allow GIF, PNG, PNG8 and JPG as tile formats
+                if (format == MgImageFormats::Png || format == MgImageFormats::Png8 || format == MgImageFormats::Jpeg || format == MgImageFormats::Gif)
+                {
+                    MgTileParameters::tileFormat = format;
+                }
+                else
+                {
+                    MgTileParameters::tileFormat = MgImageFormats::Png;
+                }
+            }
+            sm_initialized = true;
+        }
+    }
+}
+
+MgByteReader* MgTileCacheDefault::GetTile(CREFSTRING baseMapLayerGroupName,
+                                          INT32 tileColumn,
+                                          INT32 tileRow,
+                                          INT32 scaleIndex)
+{
+    Ptr<MgByteReader> ret;
+
+    MG_TRY()
+
+    if (m_map != NULL)
+        ret = GetTileForMap(baseMapLayerGroupName, tileColumn, tileRow, scaleIndex);
+    else if (m_resourceId != NULL)
+        ret = GetTileForMapDefinition(baseMapLayerGroupName, tileColumn, tileRow, scaleIndex);
+
+    MG_CATCH_AND_THROW(L"MgTileCacheDefault.GetTile")
+
+    return ret.Detach();
+}
+
+MgByteReader* MgTileCacheDefault::GetTileForMapDefinition(CREFSTRING baseMapLayerGroupName,
+                                                          INT32 tileColumn,
+                                                          INT32 tileRow,
+                                                          INT32 scaleIndex)
+{
+    Ptr<MgByteReader> ret;
+    FILE* lockFile = NULL;
+    STRING tilePathname, lockPathname;
+
+    MG_TRY()
+
+    if (NULL == (MgResourceIdentifier*)m_resourceId || baseMapLayerGroupName.empty())
+    {
+        throw new MgNullArgumentException(L"MgTileCacheDefault.GetTileForMapDefinition",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    if (scaleIndex < 0)
+    {
+        STRING buffer;
+        MgUtil::Int32ToString(scaleIndex, buffer);
+
+        MgStringCollection arguments;
+        arguments.Add(L"5");
+        arguments.Add(buffer);
+
+        throw new MgInvalidArgumentException(L"MgTileCacheDefault.GetTileForMapDefinition",
+            __LINE__, __WFILE__, &arguments, L"MgInvalidScaleIndex", NULL);
+    }
+
+    // get the service from our helper method
+    Ptr<MgResourceService> resourceService = GetResourceServiceForMapDef(m_resourceId,
+                                            L"MgTileCacheDefault.GetTileForMapDefinition");
+    // Generate tile and lock pathnames.
+    GeneratePathNames(m_resourceId, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow, tilePathname, lockPathname, false);
+
+    // If there is a dangling lock file, then attempt to remove it.
+    if (DetectTileLockFile(lockPathname))
+    {
+        // TODO: Handle the exception by displaying a tile with an error message?
+        MgFileUtil::DeleteFile(lockPathname, true);
+    }
+
+    // try getting the tile from the cache
+    ret = Get(tilePathname);
+
+    // if the reader is NULL then the tile wasn't in the cache and we
+    // need to generate it
+    while (NULL == ret)
+    {
+        // Attempt use a cached & serialized MgMap object
+        Ptr<MgMemoryStreamHelper> cachedMap;
+        STRING mapString = m_resourceId->ToString();
+        Ptr<MgMap> map;
+
+        // Protect the serialized MgMap cache with a mutex.  Stream reading is not
+        // thread safe so we need to deserialize the map within the mutex to ensure
+        // that a Rewind() is not called in the middle of a Deserialize().
+        // Lockfile test and creation is in same protected scope.
+        {
+            // Attempt to lock the tile file.
+            ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, NULL));
+
+            // Bail out if the tile file has been locked for so long.
+            if (DetectTileLockFile(lockPathname))
+            {
+                MgStringCollection arguments;
+                arguments.Add(lockPathname);
+
+                throw new MgFileIoException(L"MgTileCacheDefault.GetTileForMapDefinition",
+                    __LINE__, __WFILE__, &arguments, L"MgUnableToLockTileFile", NULL);
+            }
+
+            // try getting the tile from the cache
+            ret = Get(tilePathname);
+
+            if (NULL != ret)
+            {
+                break;  // tile was in tileCache .. done.
+            }
+
+            // Create the lock file and close it right away.
+            CreateFullPath(m_resourceId, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
+            lockFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(lockPathname), ACE_TEXT("wb"));
+
+            if (NULL == lockFile)
+            {
+                MgStringCollection arguments;
+                arguments.Add(lockPathname);
+
+                throw new MgFileIoException(L"MgTileCacheDefault.GetTileForMapDefinition",
+                    __LINE__, __WFILE__, &arguments, L"MgUnableToOpenLockFile", NULL);
+            }
+            else
+            {
+                ACE_OS::fclose(lockFile);
+            }
+
+            MapCache::const_iterator iter = sm_mapCache.find(mapString);
+            if (sm_mapCache.end() != iter)
+            {
+                cachedMap = SAFE_ADDREF((*iter).second);
+                cachedMap->Rewind();
+                Ptr<MgStream> stream = new MgStream(cachedMap);
+                map = new MgMap();
+                map->Deserialize(stream);
+            }
+            else
+            {
+                Ptr<MgSiteConnection> siteConn = new MgSiteConnection();
+                Ptr<MgUserInformation> userInfo = MgUserInformation::GetCurrentUserInfo();
+                siteConn->Open(userInfo);
+                map = new MgMap(siteConn);
+                map->Create(resourceService, m_resourceId, mapString);
+                cachedMap = new MgMemoryStreamHelper();
+                Ptr<MgStream> stream = new MgStream(cachedMap);
+                map->Serialize(stream);
+                if ((INT32)sm_mapCache.size() >= sm_mapCacheSize)
+                {
+                    ClearMapCache(L"");
+                }
+                sm_mapCache[mapString] = SAFE_ADDREF((MgMemoryStreamHelper*)cachedMap);
+            }
+        }   // end of mutex scope
+
+        double scale = map->GetFiniteDisplayScaleAt(scaleIndex);
+        map->SetViewScale(scale);
+
+        // Render the tile and cache it.
+        ret = RenderAndCacheTile(tilePathname, map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
+        break;
+    }
+
+    MG_CATCH(L"MgTileCacheDefault.GetTileForMapDefinition")
+
+    if (NULL != lockFile)
+    {
+        MgFileUtil::DeleteFile(lockPathname, false);
+    }
+
+    MG_THROW()
+
+    return ret.Detach();
+}
+
+MgByteReader* MgTileCacheDefault::GetTileForMap(CREFSTRING baseMapLayerGroupName,
+                                                INT32 tileColumn,
+                                                INT32 tileRow,
+                                                INT32 scaleIndex)
+{
+    Ptr<MgByteReader> ret;
+    FILE* lockFile = NULL;
+    STRING tilePathname, lockPathname;
+
+    MG_TRY()
+
+    if (NULL == m_map || baseMapLayerGroupName.empty())
+    {
+        throw new MgNullArgumentException(L"MgServerTileService.GetTile",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // find the finite display scale closest to the requested map scale
+    double scale = m_map->GetViewScale();
+    INT32 scaleIndex = m_map->FindNearestFiniteDisplayScaleIndex(scale);
+
+    // if we don't find a nearest scale then something is wrong with the map
+    if (scaleIndex < 0)
+    {
+        throw new MgInvalidMapDefinitionException(L"MgServerTileService.GetTile",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Detect the lock file to see if another thread is creating the tile file.
+    GeneratePathNames(m_map, scaleIndex, baseMapLayerGroupName,
+        tileColumn, tileRow, tilePathname, lockPathname, false);
+
+    // If there is a dangling lock file, then attempt to remove it.
+    if (DetectTileLockFile(lockPathname))
+    {
+        // TODO: Handle the exception by displaying a tile with an error message?
+        MgFileUtil::DeleteFile(lockPathname, true);
+    }
+
+    // try getting the tile from the cache
+    ret = Get(tilePathname);
+
+    // if the reader is NULL then the tile wasn't in the cache and we
+    // need to generate it
+    while (NULL == ret)
+    {
+        {
+            // Attemp to lock the tile file.
+            ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, NULL));
+
+            // Bail out if the tile file has been locked for so long.
+            if (DetectTileLockFile(lockPathname))
+            {
+                MgStringCollection arguments;
+                arguments.Add(lockPathname);
+
+                throw new MgFileIoException(L"MgServerTileService.GetTile",
+                    __LINE__, __WFILE__, &arguments, L"MgUnableToLockTileFile", NULL);
+            }
+
+            // try getting the tile from the cache
+            ret = Get(tilePathname);
+
+            if (NULL != ret)
+            {
+                break;
+            }
+
+            // Create the lock file and close it right away.
+            CreateFullPath(m_map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
+            lockFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(lockPathname), ACE_TEXT("wb"));
+
+            if (NULL == lockFile)
+            {
+                MgStringCollection arguments;
+                arguments.Add(lockPathname);
+
+                throw new MgFileIoException(L"MgServerTileService.GetTile",
+                    __LINE__, __WFILE__, &arguments, L"MgUnableToOpenLockFile", NULL);
+            }
+            else
+            {
+                ACE_OS::fclose(lockFile);
+            }
+        }
+
+        // Render the tile and cache it.
+        ret = RenderAndCacheTile(tilePathname, m_map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
+        break;
+    }
+
+    MG_CATCH(L"MgServerTileService.GetTile")
+
+    if (NULL != lockFile)
+    {
+        MgFileUtil::DeleteFile(lockPathname, false);
+    }
+
+    MG_THROW()
+
+    return ret.Detach();
+}
+
+                                                ///////////////////////////////////////////////////////////////////////////////
+// render a tile and store it in the cache
+MgByteReader* MgTileCacheDefault::RenderAndCacheTile(CREFSTRING tilePathname, MgMap* map, INT32 scaleIndex,
+    CREFSTRING baseMapLayerGroupName, INT32 tileColumn, INT32 tileRow)
+{
+    Ptr<MgByteReader> img;
+
+    // get a rendering service instance
+    MgServiceManager* serviceMan = MgServiceManager::GetInstance();
+    assert(NULL != serviceMan);
+    Ptr<MgRenderingService> svcRendering = dynamic_cast<MgRenderingService*>(
+        serviceMan->RequestService(MgServiceType::RenderingService));
+    assert(NULL != svcRendering);
+
+    if (svcRendering != NULL)
+    {
+        // generate the tile
+        img = svcRendering->RenderTile(map, baseMapLayerGroupName, tileColumn, tileRow);
+
+        // cache the tile
+        if (!sm_renderOnly)
+        {
+            Set(img, tilePathname);
+
+            // rewind the reader since setting the tile advances it to the end
+            if (img)
+            {
+                img->Rewind();
+            }
+        }
+    }
+
+    return img.Detach();
+}
+
+void MgTileCacheDefault::SetTile(CREFSTRING baseMapLayerGroupName,
+                                 INT32 tileColumn,
+                                 INT32 tileRow,
+                                 INT32 scaleIndex,
+                                 MgByteReader* img)
+{
+    FILE* lockFile = NULL;
+    STRING tilePathname, lockPathname;
+
+    MG_TRY()
+
+    if (NULL == img || NULL == (MgMap*)m_map || baseMapLayerGroupName.empty())
+    {
+        throw new MgNullArgumentException(L"MgTileCacheDefault.SetTile",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    if (scaleIndex < 0)
+    {
+        STRING buffer;
+        MgUtil::Int32ToString(scaleIndex, buffer);
+
+        MgStringCollection arguments;
+        arguments.Add(L"3");
+        arguments.Add(buffer);
+
+        throw new MgInvalidArgumentException(L"MgTileCacheDefault.GetTile",
+            __LINE__, __WFILE__, &arguments, L"MgInvalidScaleIndex", NULL);
+    }
+
+    // Generate tile and lock pathnames.
+    GeneratePathNames(m_map, scaleIndex, baseMapLayerGroupName,
+        tileColumn, tileRow, tilePathname, lockPathname, true);
+
+    {
+        // Attemp to lock the tile file.
+        ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
+
+        if (DetectTileLockFile(lockPathname))
+        {
+            // Attemp to remove a dangling lock file.
+            MgFileUtil::DeleteFile(lockPathname, true);
+        }
+
+        // Create the lock file and close it right away.
+        lockFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(lockPathname), ACE_TEXT("wb"));
+
+        if (NULL == lockFile)
+        {
+            MgStringCollection arguments;
+            arguments.Add(lockPathname);
+
+            throw new MgFileIoException(L"MgTileCacheDefault.SetTile",
+                __LINE__, __WFILE__, &arguments, L"MgUnableToOpenLockFile", NULL);
+        }
+        else
+        {
+            ACE_OS::fclose(lockFile);
+        }
+    }
+
+    // cache the tile
+    Set(img, tilePathname);
+
+    MG_CATCH(L"MgTileCacheDefault.SetTile")
+
+    if (NULL != lockFile)
+    {
+        MgFileUtil::DeleteFile(lockPathname, false);
+    }
+
+    MG_THROW()
+}
+
+void MgTileCacheDefault::Clear()
+{
+    if (m_map != NULL)
+    {
+        STRING basePath = GetBasePath(m_map);
+
+        // delete main map directory
+        if (!basePath.empty())
+            MgFileUtil::DeleteDirectory(basePath, true, false);
+    }
+    // the resource must be a map definition
+    else if (m_resourceId != NULL && m_resourceId->GetResourceType() == MgResourceType::MapDefinition)
+    {
+        STRING basePath = GetBasePath(m_resourceId);
+
+        // delete main map directory
+        if (!basePath.empty())
+            MgFileUtil::DeleteDirectory(basePath, true, false);
+    }
+}
+
+INT32 MgTileCacheDefault::GetDefaultTileSizeX()
+{
+    return MgTileParameters::tileWidth;
+}
+
+INT32 MgTileCacheDefault::GetDefaultTileSizeY()
+{
+    return MgTileParameters::tileHeight;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// accessor method for resource service
+MgResourceService* MgTileCacheDefault::GetResourceServiceForMapDef(MgResourceIdentifier* mapDefinition,
+                                                                   CREFSTRING funcName)
+{
+    // get service manager
+    MgServiceManager* serviceMan = MgServiceManager::GetInstance();
+    assert(NULL != serviceMan);
+
+    // Get the service from service manager
+    Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>(
+        serviceMan->RequestService(MgServiceType::ResourceService));
+    assert(NULL != resourceService);
+
+    if (!resourceService->HasPermission(mapDefinition, MgResourcePermission::ReadOnly))
+    {
+        MG_LOG_AUTHENTICATION_ENTRY(MgResources::PermissionDenied.c_str());
+
+        MgStringCollection arguments;
+        arguments.Add(mapDefinition->ToString());
+
+        throw new MgPermissionDeniedException(
+            funcName, __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+    return resourceService.Detach();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Detect if the tile file has been locked by another thread or process.
+///
+bool MgTileCacheDefault::DetectTileLockFile(CREFSTRING lockPathname)
+{
+    bool found = false;
+    struct _stat64 lockFileInfo;
+
+    // Check the lock file to see if another thread/process is writing the tile file.
+    while (MgFileUtil::GetFileStatus(lockPathname, lockFileInfo))
+    {
+        time_t currTime;
+        ACE_OS::time(&currTime);
+        INT32 diffTime = (INT32)(currTime - lockFileInfo.st_mtime);
+
+        if (diffTime < sm_creationCutoffTime)
+        {
+            ACE_OS::sleep(sm_pollingInterval);
+        }
+        else
+        {
+            found = true;
+            break;
+        }
+    }
+
+    return found;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void MgTileCacheDefault::ClearMapCache(CREFSTRING mapDefinition)
+{
+    ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
+    MapCache::iterator iter = sm_mapCache.end();
+    if (mapDefinition.empty())
+    {
+        for (iter = sm_mapCache.begin(); iter != sm_mapCache.end(); ++iter)
+        {
+            SAFE_RELEASE((*iter).second);
+            (*iter).second = NULL;
+        }
+        sm_mapCache.clear();
+
+        STRING message;
+        MgResources* resources = NULL;
+        MG_TRY()
+        resources = MgResources::GetInstance();
+        if (NULL != resources)
+        {
+            message = resources->GetResourceMessage(MgResources::ErrorDescription, L"MgMapCacheCleared", NULL);
+            MG_LOG_ERROR_ENTRY(message.c_str());
+        }
+        MG_CATCH_AND_RELEASE()
+    }
+    else
+    {
+        iter = sm_mapCache.find(mapDefinition);
+        if (sm_mapCache.end() != iter)
+        {
+            SAFE_RELEASE((*iter).second);
+            (*iter).second = NULL;
+            sm_mapCache.erase(iter);
+        }
+    }
+}
+
+void MgTileCacheDefault::GeneratePathNames(MgMap* map, int scaleIndex,
+    CREFSTRING group, int tileColumn, int tileRow,
+    STRING& tilePathname, STRING& lockPathname, bool createFullPath)
+{
+    assert(NULL != map);
+    Ptr<MgResourceIdentifier> mapDef = map->GetMapDefinition();
+
+    GeneratePathNames(mapDef, scaleIndex, group, tileColumn, tileRow,
+        tilePathname, lockPathname, createFullPath);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Generate tile and lock pathnames.
+///
+void MgTileCacheDefault::GeneratePathNames(MgResourceIdentifier* mapDef, int scaleIndex,
+    CREFSTRING group, int tileColumn, int tileRow,
+    STRING& tilePathname, STRING& lockPathname, bool createFullPath)
+{
+    STRING fileName = L"/" + GetTileName(tileRow, tileColumn) + L".";
+    STRING basePath = GetBasePath(mapDef);
+
+    if (createFullPath)
+    {
+        tilePathname = CreateFullPath(basePath, scaleIndex, group, tileColumn, tileRow);
+    }
+    else
+    {
+        tilePathname = GetFullPath(basePath, scaleIndex, group, tileColumn, tileRow);
+    }
+
+    // Generate the tile and lock pathnames
+    //     <tilePathname> = <fullPath>/<row>_<column>.png/jpg
+    //     <lockPathname> = <fullPath>/<row>_<column>.lck
+    tilePathname += fileName;
+    lockPathname = tilePathname;
+    if (MgTileParameters::tileFormat == MgImageFormats::Jpeg)
+    {
+        tilePathname += L"jpg";
+    }
+    else if (MgTileParameters::tileFormat == MgImageFormats::Gif)
+    {
+        tilePathname += L"gif";
+    }
+    else
+    {
+        tilePathname += L"png";
+    }
+
+    lockPathname += L"lck";
+}
+
+// Get the filename corresponding to the specified row and column.
+// No file extension is added.
+STRING MgTileCacheDefault::GetTileName(int tileRow, int tileColumn)
+{
+    return GetTileIndexString(tileRow, sm_tileRowsPerFolder) + L"_" +
+           GetTileIndexString(tileColumn, sm_tileColumnsPerFolder);
+}
+
+// When a tile is stored in a folder, the index value of the parent folder
+// is subtracted from the overall tile index.
+// e.g. If we store 30 rows of tiles per folder, a tile with overall row
+// index 73 will be stored in the row folder "R60" with a row index of 13.
+// Note: Negative values are maintained even near the origin, so a tile with
+// an overall row index of -13 would be stored in row folder "R-0" with a
+// row index of -13.
+STRING MgTileCacheDefault::GetTileIndexString(int tileIndex, int tilesPerFolder)
+{
+    STRING name;
+
+    // Determine the offset of this tile within the folder
+    int tileNameIndex = tileIndex % tilesPerFolder;
+    if(tileIndex < 0 && tileNameIndex == 0)
+    {
+        name = L"-0";
+    }
+    else
+    {
+        MgUtil::Int32ToString(tileNameIndex, name);
+    }
+    return name;
+}
+
+// Get the folder name corresponding to the specified scale index
+STRING MgTileCacheDefault::GetScaleIndexFolder(int scaleIndex)
+{
+    STRING scaleIndexString;
+    MgUtil::Int32ToString(scaleIndex, scaleIndexString);
+    return SCALE_INDEX_PREFIX + scaleIndexString;
+}
+
+// Get the folder name corresponding to the specified tile row
+STRING MgTileCacheDefault::GetRowFolder(int tileRow)
+{
+    return GetFolder(ROW_PREFIX, tileRow, sm_tileRowsPerFolder);
+}
+
+STRING MgTileCacheDefault::CreateFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
+{
+    assert(!basePath.empty());
+    STRING fullPath = basePath;
+
+    // Create base directory if it does not exist.
+    MgFileUtil::CreateDirectory(fullPath, false);
+
+    // Create scale directory if it does not exist.
+    fullPath += L"/";
+    fullPath += GetScaleIndexFolder(scaleIndex);
+    MgFileUtil::CreateDirectory(fullPath, false);
+
+    // Create group directory if it does not exist.
+    fullPath += L"/";
+    fullPath += group;
+    MgFileUtil::CreateDirectory(fullPath, false);
+
+    // Create row directory if it does not exist.
+    fullPath += L"/";
+    fullPath += GetRowFolder(tileRow);
+    MgFileUtil::CreateDirectory(fullPath, false);
+
+    // Create column directory if it does not exist.
+    fullPath += L"/";
+    fullPath += GetColumnFolder(tileColumn);
+    MgFileUtil::CreateDirectory(fullPath, false);
+
+    return fullPath;
+}
+
+STRING MgTileCacheDefault::CreateFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
+{
+    return CreateFullPath(GetBasePath(mapDef), scaleIndex, group, tileColumn, tileRow);
+}
+
+STRING MgTileCacheDefault::CreateFullPath(MgMap* map, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
+{
+    return CreateFullPath(GetBasePath(map), scaleIndex, group, tileColumn, tileRow);
+}
+
+// gets the base path to use with the tile cache for the given map
+STRING MgTileCacheDefault::GetBasePath(MgMap* map)
+{
+    assert(NULL != map);
+    Ptr<MgResourceIdentifier> mapDef = map->GetMapDefinition();
+    return GetBasePath(mapDef);
+}
+
+// gets the base path to use with the tile cache for the given map definition resource
+STRING MgTileCacheDefault::GetBasePath(MgResourceIdentifier* mapDef)
+{
+    assert(mapDef != NULL);
+    assert(mapDef->GetResourceType() == MgResourceType::MapDefinition);
+    STRING mapPath;
+
+    if (mapDef->GetRepositoryType() == MgRepositoryType::Library)
+    {
+        // for maps in the library repository the path+name is unique
+        mapPath  = mapDef->GetPath();
+        mapPath += L"_";
+        mapPath += mapDef->GetName();
+    }
+    else if (mapDef->GetRepositoryType() == MgRepositoryType::Session)
+    {
+        // for maps in the session repository we use the session + path + map name
+        mapPath  = mapDef->GetRepositoryName();
+        mapPath += L"_";
+
+        STRING resourcePath  = mapDef->GetPath();
+
+        if (!resourcePath.empty())
+        {
+            mapPath += resourcePath;
+            mapPath += L"_";
+        }
+
+        mapPath += mapDef->GetName();
+    }
+    else
+    {
+        // shouldn't get here
+        assert(false);
+        return mapPath;
+    }
+
+    // for safety
+    mapPath = MgUtil::ReplaceString(mapPath, L"/", L"_");
+    mapPath = MgUtil::ReplaceString(mapPath, L":", L"_");
+
+    // Build the base path using format "%ls%ls":
+    //     <basePath> = <tileCachePath><mapPath>
+    STRING basePath = sm_path;
+    basePath += mapPath;
+
+    return basePath;
+}
+
+// gets the full path to use with the tile cache for the given base path / scale index / group
+STRING MgTileCacheDefault::GetFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
+{
+    // Build full path
+    //     <fullPath> = <basePath>/<scaleIndex>/<group>/<rowFolder>/<columnFolder>
+    assert(!basePath.empty());
+    STRING fullPath = basePath;
+
+    fullPath += L"/";
+    fullPath += GetScaleIndexFolder(scaleIndex);
+
+    fullPath += L"/";
+    fullPath += group;
+
+    fullPath += L"/";
+    fullPath += GetRowFolder(tileRow);
+
+    fullPath += L"/";
+    fullPath += GetColumnFolder(tileColumn);
+
+    return fullPath;
+}
+
+// gets the full path to use with the tile cache for the given map definition / scale index / group
+STRING MgTileCacheDefault::GetFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
+{
+    return GetFullPath(GetBasePath(mapDef), scaleIndex, group, tileColumn, tileRow);
+}
+
+// gets the full path to use with the tile cache for the given map / scale index / group
+STRING MgTileCacheDefault::GetFullPath(MgMap* map, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
+{
+    assert(NULL != map);
+    Ptr<MgResourceIdentifier> mapDef = map->GetMapDefinition();
+    return GetFullPath(mapDef, scaleIndex, group, tileColumn, tileRow);
+}
+
+// Get the folder name corresponding to the specified tile column
+STRING MgTileCacheDefault::GetColumnFolder(int tileColumn)
+{
+    return GetFolder(COLUMN_PREFIX, tileColumn, sm_tileColumnsPerFolder);
+}
+
+// Get the parent folder for a given row or column
+STRING MgTileCacheDefault::GetFolder(STRING prefix, int tileIndex, int tilesPerFolder)
+{
+    STRING folder;
+
+    // Determine which folder contains this tile
+    int folderIndex = tileIndex / tilesPerFolder;
+    int firstTileIndex = folderIndex * tilesPerFolder;
+    if(tileIndex < 0 && firstTileIndex == 0)
+    {
+        folder = L"-0";
+    }
+    else
+    {
+        MgUtil::Int32ToString(firstTileIndex, folder);
+    }
+    return prefix + folder;
+}
+
+MgByteReader* MgTileCacheDefault::Get(CREFSTRING path)
+{
+    Ptr<MgByteReader> ret;
+
+    MG_TRY()
+
+    if (MgFileUtil::PathnameExists(path))
+    {
+        Ptr<MgByteSource> byteSource = new MgByteSource(path, false);
+
+        if (MgTileParameters::tileFormat == MgImageFormats::Jpeg)
+        {
+            byteSource->SetMimeType(MgMimeType::Jpeg);
+        }
+        else if (MgTileParameters::tileFormat == MgImageFormats::Gif)
+        {
+            byteSource->SetMimeType(MgMimeType::Gif);
+        }
+        else
+        {
+            byteSource->SetMimeType(MgMimeType::Png);
+        }
+
+        ret = byteSource->GetReader();
+    }
+
+    MG_CATCH_AND_RELEASE()
+
+    return ret.Detach();
+}
+
+void MgTileCacheDefault::Set(MgByteReader* img, CREFSTRING path)
+{
+    if (img != NULL)
+    {
+        Ptr<MgByteSink> byteSink = new MgByteSink(img);
+
+        byteSink->ToFile(path);
+    }
+}
\ No newline at end of file

Added: sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.h
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.h	                        (rev 0)
+++ sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.h	2014-05-30 15:31:40 UTC (rev 8177)
@@ -0,0 +1,119 @@
+//
+//  Copyright (C) 2004-2014 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+#ifndef _MG_TILE_CACHE_DEFAULT_H_
+#define _MG_TILE_CACHE_DEFAULT_H_
+
+#include "TileCache.h"
+
+class MG_SERVER_TILE_API MgTileCacheDefault : public MgTileCache
+{
+public:
+    MgTileCacheDefault(MgMap* map);
+    MgTileCacheDefault(MgResourceIdentifier* resource);
+    virtual ~MgTileCacheDefault();
+
+    static void Initialize();
+
+    virtual MgByteReader* GetTile(CREFSTRING baseMapLayerGroupName,
+                                  INT32 tileColumn,
+                                  INT32 tileRow,
+                                  INT32 scaleIndex);
+
+    virtual void SetTile(CREFSTRING baseMapLayerGroupName,
+                         INT32 tileColumn,
+                         INT32 tileRow,
+                         INT32 scaleIndex,
+                         MgByteReader* img);
+
+    virtual void Clear();
+
+    virtual INT32 GetDefaultTileSizeX();
+
+    virtual INT32 GetDefaultTileSizeY();
+
+    void ClearMapCache(CREFSTRING mapName);
+
+protected:
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+private:
+    MgByteReader* GetTileForMapDefinition(CREFSTRING baseMapLayerGroupName,
+                                          INT32 tileColumn,
+                                          INT32 tileRow,
+                                          INT32 scaleIndex);
+
+    MgByteReader* GetTileForMap(CREFSTRING baseMapLayerGroupName,
+                                INT32 tileColumn,
+                                INT32 tileRow,
+                                INT32 scaleIndex);
+
+    MgByteReader* RenderAndCacheTile(CREFSTRING tilePathname, MgMap* map, INT32 scaleIndex, CREFSTRING baseMapLayerGroupName, INT32 tileColumn, INT32 tileRow);
+
+    void Set(MgByteReader* img, CREFSTRING path);
+    MgByteReader* Get(CREFSTRING path);
+
+    void GeneratePathNames(MgResourceIdentifier* mapDef, int scaleIndex,
+        CREFSTRING group, int tileColumn, int tileRow,
+        STRING& tilePathname, STRING& lockPathname, bool createFullPath);
+    void GeneratePathNames(MgMap* map, int scaleIndex,
+        CREFSTRING group, int tileColumn, int tileRow,
+        STRING& tilePathname, STRING& lockPathname, bool createFullPath);
+    
+    STRING GetBasePath(MgResourceIdentifier* mapDef);
+    STRING GetBasePath(MgMap* map);
+
+    STRING GetFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
+    STRING GetFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
+    STRING GetFullPath(MgMap* map, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
+
+    STRING CreateFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
+    STRING CreateFullPath(MgMap* map, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
+    STRING CreateFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
+
+    STRING GetScaleIndexFolder(int scaleIndex);
+    STRING GetRowFolder(int tileRow);
+    STRING GetColumnFolder(int tileColumn);
+    STRING GetFolder(STRING prefix, int tileIndex, int tilesPerFolder);
+
+    STRING GetTileName(int tileRow, int tileColumn);
+    STRING GetTileIndexString(int tileIndex, int tilesPerFolder);
+
+    MgResourceService* GetResourceServiceForMapDef(MgResourceIdentifier* mapDefinition, CREFSTRING funcName);
+    bool DetectTileLockFile(CREFSTRING lockPathname);
+
+    Ptr<MgResourceIdentifier> m_resourceId;
+    Ptr<MgMap> m_map;
+
+    static STRING sm_path;
+    static INT32 sm_tileColumnsPerFolder;
+    static INT32 sm_tileRowsPerFolder;
+
+    typedef std::map<STRING, MgMemoryStreamHelper*> MapCache;
+
+    static ACE_Recursive_Thread_Mutex sm_mutex;
+    static MapCache sm_mapCache;
+    static bool sm_initialized;
+    static bool sm_renderOnly;
+    static INT32 sm_creationCutoffTime;
+    static INT32 sm_pollingInterval;
+    static INT32 sm_mapCacheSize;
+};
+
+#endif
\ No newline at end of file

Modified: sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.cpp
===================================================================
--- sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.cpp	2014-05-30 09:44:22 UTC (rev 8176)
+++ sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.cpp	2014-05-30 15:31:40 UTC (rev 8177)
@@ -855,7 +855,7 @@
     try
     {
         // call the API with a NULL argument
-        CPPUNIT_ASSERT_THROW_MG(m_svcTile->ClearCache(NULL), MgNullArgumentException*);
+        CPPUNIT_ASSERT_THROW_MG(m_svcTile->ClearCache((MgMap*)NULL), MgNullArgumentException*);
 
         // call the API with a map having a different name
         Ptr<MgMap> map = CreateMap(L"blah");



More information about the mapguide-commits mailing list