[mapguide-commits] r8180 - in sandbox/jng/tiling: Common/MapGuideCommon Common/MapGuideCommon/Exception Common/MapGuideCommon/MapLayer Common/MapGuideCommon/Services Common/MapGuideCommon/System Server/src/PostBuild Server/src/Services/Tile Server/src/UnitTesting UnitTest/TestData/TileService

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Mon Jun 2 15:33:06 PDT 2014


Author: jng
Date: 2014-06-02 15:33:06 -0700 (Mon, 02 Jun 2014)
New Revision: 8180

Added:
   sandbox/jng/tiling/Common/MapGuideCommon/Exception/UnknownTileProviderException.cpp
   sandbox/jng/tiling/Common/MapGuideCommon/Exception/UnknownTileProviderException.h
   sandbox/jng/tiling/UnitTest/TestData/TileService/UT_BaseMap.tsd
   sandbox/jng/tiling/UnitTest/TestData/TileService/UT_LinkedTileSet.mdf
Modified:
   sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.h
   sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.vcxproj
   sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.vcxproj.filters
   sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommonBuild.cpp
   sandbox/jng/tiling/Common/MapGuideCommon/MapLayer/Map.cpp
   sandbox/jng/tiling/Common/MapGuideCommon/MapLayer/Map.h
   sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.cpp
   sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.h
   sandbox/jng/tiling/Common/MapGuideCommon/System/MapGuideCommonClassId.h
   sandbox/jng/tiling/Server/src/PostBuild/PostBuild.mak
   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/TileCacheDefault.cpp
   sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.h
   sandbox/jng/tiling/Server/src/UnitTesting/TestMdfModel.cpp
   sandbox/jng/tiling/Server/src/UnitTesting/TestMdfModel.h
   sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.cpp
   sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.h
Log:
Add first cut of shareable tile sets:
 - Add a new implementation of MgTileCache (MgTileCacheDefaultProvider) that inherits from MgTileCacheDefaults and overrides several key methods, to return values that are plugged in by the TileSetDefinition resource.
 - Modify MgMap to allow creation from
   - A Map Definition
   - A Map Definition that links to a Tile Set Definition
   - A Tile Set Definition
   This is to allow the tile rendering off of Tile Set Definitions to work as they require a MgMap be passed to the RenderTile() method.
 - Add new unit tests
   - MdfModel test to ensure a TileSetDefinition is properly deserialized
   - Tile Service tests to exercise multi-threaded GetTile() calls to a tile set definition and clearing the cache of a tile set definition
   - MgMap tests to exercise creation from the new input resource permutations

Added: sandbox/jng/tiling/Common/MapGuideCommon/Exception/UnknownTileProviderException.cpp
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/Exception/UnknownTileProviderException.cpp	                        (rev 0)
+++ sandbox/jng/tiling/Common/MapGuideCommon/Exception/UnknownTileProviderException.cpp	2014-06-02 22:33:06 UTC (rev 8180)
@@ -0,0 +1,40 @@
+//
+//  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
+//
+
+#include "MapGuideCommon.h"
+
+IMPLEMENT_EXCEPTION_DEFAULTS(MgUnknownTileProviderException, MgApplicationException)
+
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Construct a MgUnknownTileProviderException object.
+///
+MgUnknownTileProviderException::MgUnknownTileProviderException(CREFSTRING methodName,
+    INT32 lineNumber, CREFSTRING fileName, MgStringCollection* whatArguments,
+    CREFSTRING whyMessageId, MgStringCollection* whyArguments) throw() :
+    MgApplicationException(methodName, lineNumber, fileName,
+        whatArguments, whyMessageId, whyArguments)
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Destruct the object.
+///
+MgUnknownTileProviderException::~MgUnknownTileProviderException() throw()
+{
+}

Added: sandbox/jng/tiling/Common/MapGuideCommon/Exception/UnknownTileProviderException.h
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/Exception/UnknownTileProviderException.h	                        (rev 0)
+++ sandbox/jng/tiling/Common/MapGuideCommon/Exception/UnknownTileProviderException.h	2014-06-02 22:33:06 UTC (rev 8180)
@@ -0,0 +1,69 @@
+//
+//  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_UNKNOWN_TILE_PROVIDER_EXCEPTION_H_
+#define MG_UNKNOWN_TILE_PROVIDER_EXCEPTION_H_
+
+/// \ingroup Exceptions_Module
+
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Thrown when a tile set definition contains an unknown tile provider
+///
+class MG_MAPGUIDE_API MgUnknownTileProviderException : public MgApplicationException
+{
+    DECLARE_CLASSNAME(MgUnknownTileProviderException)
+
+EXTERNAL_API:
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Construct a MgUnknownTileProviderException object.
+    ///
+    /// \param methodName
+    /// Name of the method where the exception occurred.
+    /// \param lineNumber
+    /// Line number where the exception occurred.
+    /// \param fileName
+    /// File name where the exception occurred.
+    /// \param whatArguments
+    /// Collection of arguments used to format the message that describes what the exception is.
+    /// \param whyMessageId
+    /// ID of the message that describes why the exception occurs.
+    /// \param whyArguments
+    /// Collection of arguments used to format the message that describes why the exception occurs.
+    ///
+    MgUnknownTileProviderException(CREFSTRING methodName, INT32 lineNumber,
+        CREFSTRING fileName, MgStringCollection* whatArguments,
+        CREFSTRING whyMessageId, MgStringCollection* whyArguments) throw();
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Destructor for a MgUnknownTileProviderException object.
+    ///
+    virtual ~MgUnknownTileProviderException() throw();
+
+INTERNAL_API:
+
+    DECLARE_EXCEPTION_DEFAULTS(MgUnknownTileProviderException)
+
+CLASS_ID:
+
+    static const INT32 m_cls_id = MapGuide_Exception_MgUnknownTileProviderException;
+};
+
+#endif

Modified: sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.h
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.h	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.h	2014-06-02 22:33:06 UTC (rev 8180)
@@ -116,6 +116,7 @@
 #include "Exception/SessionNotFoundException.h"
 #include "Exception/StylizeLayerFailedException.h"
 #include "Exception/UnauthorizedAccessException.h"
+#include "Exception/UnknownTileProviderException.h"
 #include "Exception/UnsupportedProviderThreadModelException.h"
 #include "Exception/UriFormatException.h"
 

Modified: sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.vcxproj
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.vcxproj	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.vcxproj	2014-06-02 22:33:06 UTC (rev 8180)
@@ -198,6 +198,12 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="Exception\UnknownTileProviderException.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="MapLayer\Layer.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -939,6 +945,7 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="Exception\UnknownTileProviderException.h" />
     <ClInclude Include="MapLayer\Layer.h" />
     <ClInclude Include="MapLayer\Map.h" />
     <ClInclude Include="MapLayer\Selection.h" />

Modified: sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.vcxproj.filters
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.vcxproj.filters	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommon.vcxproj.filters	2014-06-02 22:33:06 UTC (rev 8180)
@@ -394,6 +394,9 @@
     <ClCompile Include="Util\TimerUtil.cpp">
       <Filter>Util</Filter>
     </ClCompile>
+    <ClCompile Include="Exception\UnknownTileProviderException.cpp">
+      <Filter>Exception</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="MapLayer\Layer.h">
@@ -769,6 +772,9 @@
     <ClInclude Include="Util\TimerUtil.h">
       <Filter>Util</Filter>
     </ClInclude>
+    <ClInclude Include="Exception\UnknownTileProviderException.h">
+      <Filter>Exception</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="MapGuideCommon.rc" />

Modified: sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommonBuild.cpp
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommonBuild.cpp	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Common/MapGuideCommon/MapGuideCommonBuild.cpp	2014-06-02 22:33:06 UTC (rev 8180)
@@ -72,6 +72,7 @@
 #include  "Exception/SessionNotFoundException.cpp"
 #include  "Exception/StylizeLayerFailedException.cpp"
 #include  "Exception/UnauthorizedAccessException.cpp"
+#include  "Exception/UnknownTileProviderException.cpp"
 #include  "Exception/UnsupportedProviderThreadModelException.cpp"
 #include  "Exception/UriFormatException.cpp"
 #include  "MapLayer/Layer.cpp"

Modified: sandbox/jng/tiling/Common/MapGuideCommon/MapLayer/Map.cpp
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/MapLayer/Map.cpp	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Common/MapGuideCommon/MapLayer/Map.cpp	2014-06-02 22:33:06 UTC (rev 8180)
@@ -111,10 +111,33 @@
 // Initializes a new Map object.
 // This method is used for Mg Viewers or for offline map production.
 //
-void MgMap::Create(MgResourceService* resourceService, MgResourceIdentifier* mapDefinition, CREFSTRING mapName)
+void MgMap::Create(MgResourceService* resourceService, MgResourceIdentifier* resource, CREFSTRING mapName)
 {
     MG_TRY()
 
+    if (resource->GetResourceType() == MgResourceType::MapDefinition)
+        CreateFromMapDefinition(resourceService, resource, mapName);
+    else if (resource->GetResourceType() == MgResourceType::TileSetDefinition)
+        CreateFromTileSet(resourceService, resource, mapName);
+    else
+        throw new MgInvalidResourceTypeException(L"MgMap.Create", __LINE__, __WFILE__, NULL, L"", NULL);
+
+    MG_CATCH_AND_THROW(L"MgMap.Create")
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initializes a new MgMap object given a map definition and a name for the map.
+/// This method is used for MapGuide Viewers or for offline map production.
+///
+void MgMap::Create(MgResourceIdentifier* mapDefinition, CREFSTRING mapName)
+{
+    Create(NULL, mapDefinition, mapName);
+}
+
+void MgMap::CreateFromMapDefinition(MgResourceService* resourceService, MgResourceIdentifier* mapDefinition, CREFSTRING mapName)
+{
+    MG_TRY()
+
     InitializeResourceService(resourceService);
     m_trackChangesDisabled = true;
 
@@ -151,17 +174,6 @@
     assert(mdef.get() != NULL);
 
     MgGeometryFactory gf;
-
-    const Box2D& extent = mdef->GetExtents();
-    Ptr<MgCoordinate> lowerLeft = gf.CreateCoordinateXY(extent.GetMinX(), extent.GetMinY());
-    Ptr<MgCoordinate> upperRight = gf.CreateCoordinateXY(extent.GetMaxX(), extent.GetMaxY());
-    m_mapExtent = new MgEnvelope(lowerLeft, upperRight);
-    m_dataExtent = new MgEnvelope(lowerLeft, upperRight);
-    m_backColor = mdef->GetBackgroundColor();
-
-    Ptr<MgCoordinate> coordCenter = gf.CreateCoordinateXY(extent.GetMinX() + (extent.GetMaxX() - extent.GetMinX()) / 2,
-                                                          extent.GetMinY() + (extent.GetMaxY() - extent.GetMinY()) / 2);
-    m_center = gf.CreatePoint(coordCenter);
     Ptr<MgResourceIdentifier> tileSetDefId;
 
     //If this Map Definition links to a Tile Set Definition, its coordinate system takes precedence
@@ -189,10 +201,47 @@
         assert(tdef.get() != NULL);
 
         m_srs = tdef->GetCoordinateSystem();
+
+        //If tile CS is not the same as map def CS, then the bounds of the map def need to be transformed
+        if (m_srs != mdef->GetCoordinateSystem())
+        {
+            Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+            Ptr<MgCoordinateSystem> mapCs = csFactory->Create(mdef->GetCoordinateSystem());
+            Ptr<MgCoordinateSystem> tileCs = csFactory->Create(tdef->GetCoordinateSystem());
+            Ptr<MgCoordinateSystemTransform> trans = csFactory->GetTransform(mapCs, tileCs);
+
+            const Box2D& extent = mdef->GetExtents();
+            Ptr<MgCoordinate> lowerLeft = gf.CreateCoordinateXY(extent.GetMinX(), extent.GetMinY());
+            Ptr<MgCoordinate> upperRight = gf.CreateCoordinateXY(extent.GetMaxX(), extent.GetMaxY());
+            Ptr<MgEnvelope> mapExtent = new MgEnvelope(lowerLeft, upperRight);
+            Ptr<MgEnvelope> dataExtent = new MgEnvelope(lowerLeft, upperRight);
+
+            m_mapExtent = mapExtent->Transform(trans);
+            m_dataExtent = mapExtent->Transform(trans);
+
+            Ptr<MgCoordinate> ll = mapExtent->GetLowerLeftCoordinate();
+            Ptr<MgCoordinate> ur = mapExtent->GetUpperRightCoordinate();
+            
+            Ptr<MgCoordinate> coordCenter = gf.CreateCoordinateXY(ll->GetX() + (ur->GetX() - ll->GetX()) / 2,
+                                                                  ll->GetY() + (ur->GetY() - ll->GetY()) / 2);
+
+            m_center = gf.CreatePoint(coordCenter);
+        }
     }
     else
     {
         m_srs = mdef->GetCoordinateSystem();
+
+        const Box2D& extent = mdef->GetExtents();
+        Ptr<MgCoordinate> lowerLeft = gf.CreateCoordinateXY(extent.GetMinX(), extent.GetMinY());
+        Ptr<MgCoordinate> upperRight = gf.CreateCoordinateXY(extent.GetMaxX(), extent.GetMaxY());
+        m_mapExtent = new MgEnvelope(lowerLeft, upperRight);
+        m_dataExtent = new MgEnvelope(lowerLeft, upperRight);
+        m_backColor = mdef->GetBackgroundColor();
+
+        Ptr<MgCoordinate> coordCenter = gf.CreateCoordinateXY(extent.GetMinX() + (extent.GetMaxX() - extent.GetMinX()) / 2,
+                                                              extent.GetMinY() + (extent.GetMaxY() - extent.GetMinY()) / 2);
+        m_center = gf.CreatePoint(coordCenter);
     }
 
     //Calculate the meter per unit for the given coordinate system
@@ -381,11 +430,16 @@
             STRING groupName = baseGroup->GetName();
             Ptr<MgLayerGroup> rtGroup;
             if (NULL != (MgResourceIdentifier*)tileSetDefId)
+            {
                 rtGroup = new MgLayerGroup(groupName, tileSetDefId);
+                rtGroup->SetLayerGroupType(MgLayerGroupType::BaseMapFromTileSet);
+            }
             else
+            {
                 rtGroup = new MgLayerGroup(groupName);
+                rtGroup->SetLayerGroupType(MgLayerGroupType::BaseMap);
+            }
             rtGroup->SetVisible(baseGroup->IsVisible());
-            rtGroup->SetLayerGroupType(MgLayerGroupType::BaseMap);
             rtGroup->SetDisplayInLegend(baseGroup->IsShowInLegend());
             rtGroup->SetExpandInLegend(baseGroup->IsExpandInLegend());
             rtGroup->SetLegendLabel(baseGroup->GetLegendLabel());
@@ -482,16 +536,216 @@
     // there's nothing to unpack anymore in this case
     m_unpackedLayersGroups = true;
 
-    MG_CATCH_AND_THROW(L"MgMap.Create")
+    MG_CATCH_AND_THROW(L"MgMap.CreateFromMapDefinition")
 }
 
-///////////////////////////////////////////////////////////////////////////////
-/// Initializes a new MgMap object given a map definition and a name for the map.
-/// This method is used for MapGuide Viewers or for offline map production.
-///
-void MgMap::Create(MgResourceIdentifier* mapDefinition, CREFSTRING mapName)
+void MgMap::CreateFromTileSet(MgResourceService* resourceService, MgResourceIdentifier* tileSetDefId, CREFSTRING mapName)
 {
-    Create(NULL, mapDefinition, mapName);
+    MG_TRY()
+
+    InitializeResourceService(resourceService);
+    m_trackChangesDisabled = true;
+
+    m_mapDefinitionId = NULL;
+    m_name = mapName;
+
+    // reset the colorlist from our layers (std::list dtor clears the list)
+    delete m_colorPalette;
+    m_colorPalette = NULL;  // initialize to empty (lazy as its only used for 8bit color)
+
+    // generate a unique id for this map
+    MgUtil::GenerateUuid(m_objectId);
+
+    // get the map definition from the resource repository
+    Ptr<MgByteReader> content = m_resourceService->GetResourceContent(tileSetDefId);
+    Ptr<MgByteSink> sink = new MgByteSink(content);
+    Ptr<MgByte> bytes = sink->ToBuffer();
+
+    // parse the map definition
+    MdfParser::SAX2Parser parser;
+    parser.ParseString((const char*)bytes->Bytes(), bytes->GetLength());
+
+    if (!parser.GetSucceeded())
+    {
+        STRING errorMsg = parser.GetErrorMessage();
+        MgStringCollection arguments;
+        arguments.Add(errorMsg);
+        throw new MgInvalidMapDefinitionException(L"MgMap.Create", __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+
+    // build the runtime map object from the parsed definition
+    std::auto_ptr<MdfModel::TileSetDefinition> tdef(parser.DetachTileSetDefinition());
+    assert(tdef.get() != NULL);
+
+    MgGeometryFactory gf;
+
+    const Box2D& extent = tdef->GetExtents();
+    Ptr<MgCoordinate> lowerLeft = gf.CreateCoordinateXY(extent.GetMinX(), extent.GetMinY());
+    Ptr<MgCoordinate> upperRight = gf.CreateCoordinateXY(extent.GetMaxX(), extent.GetMaxY());
+    m_mapExtent = new MgEnvelope(lowerLeft, upperRight);
+    m_dataExtent = new MgEnvelope(lowerLeft, upperRight);
+    m_backColor = L"FFFFFFFF";
+
+    Ptr<MgCoordinate> coordCenter = gf.CreateCoordinateXY(extent.GetMinX() + (extent.GetMaxX() - extent.GetMinX()) / 2,
+                                                          extent.GetMinY() + (extent.GetMaxY() - extent.GetMinY()) / 2);
+    m_center = gf.CreatePoint(coordCenter);
+    m_srs = tdef->GetCoordinateSystem();
+
+    //Calculate the meter per unit for the given coordinate system
+    m_metersPerUnit = 1.0; // assume a default value
+    if (m_srs.length() > 0)
+    {
+        Ptr<MgCoordinateSystemFactory> coordFactory = new MgCoordinateSystemFactory();
+        Ptr<MgCoordinateSystem> coordSys = coordFactory->Create(m_srs);
+        if (coordSys != NULL)
+        {
+            m_metersPerUnit = coordSys->ConvertCoordinateSystemUnitsToMeters(1.0);
+        }
+    }
+
+    // clear the collections
+    m_layers->Clear();
+    m_groups->Clear();
+    m_changeLists->Clear();
+    m_finiteDisplayScales.clear();
+
+    double displayOrder = LAYER_ZORDER_TOP;
+
+    //Get all the layersand get the contents of them in a single request.
+    Ptr<MgStringCollection> layerIds = new MgStringCollection();
+    BaseMapLayerGroupCollection* baseLayerGroups = tdef->GetBaseMapLayerGroups();
+    if (baseLayerGroups)
+    {
+        for(int i = 0; i < baseLayerGroups->GetCount(); i ++)
+        {
+            BaseMapLayerGroup* baseGroup = (BaseMapLayerGroup*)baseLayerGroups->GetAt(i);
+            BaseMapLayerCollection* baseLayers = baseGroup->GetLayers();
+            if(baseLayers)
+            {
+                for(int j = 0; j < baseLayers->GetCount(); j ++)
+                {
+                    layerIds->Add(baseLayers->GetAt(j)->GetLayerResourceID());
+                }
+            }
+        }
+    }
+    std::map<STRING, STRING> layerContentPair;
+    if (layerIds->GetCount() != 0)
+    {
+        Ptr<MgStringCollection> layerContents = m_resourceService->GetResourceContents(layerIds, NULL);
+        for(int i = 0; i < layerIds->GetCount(); i ++)
+        {
+            layerContentPair.insert(std::pair<STRING, STRING>(layerIds->GetItem(i), layerContents->GetItem(i)));
+        }
+    }
+
+    // BaseMapLayerGroups and BaseMapLayers come at the end
+    BaseMapLayerGroupCollection* baseGroups = tdef->GetBaseMapLayerGroups();
+    if (baseGroups)
+    {
+        for(int i = 0; i < baseGroups->GetCount(); i++)
+        {
+            BaseMapLayerGroup* baseGroup = (BaseMapLayerGroup*)baseGroups->GetAt(i);
+
+            //create a runtime group from this group and add it to the group collection
+            STRING groupName = baseGroup->GetName();
+            Ptr<MgLayerGroup> rtGroup;
+            rtGroup = new MgLayerGroup(groupName, tileSetDefId);
+            rtGroup->SetVisible(baseGroup->IsVisible());
+            rtGroup->SetLayerGroupType(MgLayerGroupType::BaseMapFromTileSet);
+            rtGroup->SetDisplayInLegend(baseGroup->IsShowInLegend());
+            rtGroup->SetExpandInLegend(baseGroup->IsExpandInLegend());
+            rtGroup->SetLegendLabel(baseGroup->GetLegendLabel());
+
+            // NOTE: base groups do not have a parent group
+
+            m_groups->Add(rtGroup);
+
+            // process the base map layers for this group
+            BaseMapLayerCollection* baseLayers = baseGroup->GetLayers();
+            if (baseLayers)
+            {
+                for(int j = 0; j < baseLayers->GetCount(); j++, displayOrder += LAYER_ZORDER_INCR)
+                {
+                    BaseMapLayer* baseLayer = (BaseMapLayer*)baseLayers->GetAt(j);
+
+                    // base layers should always be visible
+                    assert(baseLayer->IsVisible());
+                    if (baseLayer->IsVisible())
+                    {
+                        //create a runtime layer from this base layer and add it to the layer collection
+                        Ptr<MgResourceIdentifier> layerDefId = new MgResourceIdentifier(baseLayer->GetLayerResourceID());
+                        Ptr<MgLayerBase> rtLayer = new MgLayer(layerDefId, m_resourceService, true, false);
+                        rtLayer->SetLayerResourceContent(layerContentPair[layerDefId->ToString()]);
+                        rtLayer->SetName(baseLayer->GetName());
+                        rtLayer->SetVisible(true);
+                        rtLayer->SetLayerType(MgLayerType::BaseMap);
+                        rtLayer->SetDisplayInLegend(baseLayer->IsShowInLegend());
+                        rtLayer->SetExpandInLegend(baseLayer->IsExpandInLegend());
+                        rtLayer->SetLegendLabel(baseLayer->GetLegendLabel());
+                        rtLayer->SetSelectable(baseLayer->IsSelectable());
+                        rtLayer->SetDisplayOrder(displayOrder);
+
+                        m_layers->Add(rtLayer);
+
+                        // attach the layer to its group
+                        rtLayer->SetGroup(rtGroup);
+                    }
+                }
+            }
+        }
+    }
+
+    // Now that we've added all the layers (dynamic and base map) to the m_layers collection,
+    // bulk load the identity properties for all layers
+    Ptr<MgSiteConnection> siteConn;
+    if (m_siteConnection.p != NULL)
+    {
+        siteConn = SAFE_ADDREF((MgSiteConnection*)m_siteConnection);
+    }
+    else
+    {
+        Ptr<MgUserInformation> userInfo = m_resourceService->GetUserInfo();
+        siteConn = new MgSiteConnection();
+        siteConn->Open(userInfo);
+    }
+    Ptr<MgFeatureService> featureService = dynamic_cast<MgFeatureService*>(siteConn->CreateService(MgServiceType::FeatureService));
+    BulkLoadIdentityProperties(featureService);
+
+    // build the sorted list of finite display scales
+    SORTEDSCALES sortedScales;
+    DisplayScaleCollection* displayScales = tdef->GetFiniteDisplayScales();
+    if (displayScales)
+    {
+        for(int i = 0; i < displayScales->GetCount(); i++)
+        {
+            DisplayScale* displayScale = displayScales->GetAt(i);
+            double scale = displayScale->GetValue();
+
+            // skip non-positive scales
+            if (scale <= 0.0)
+                continue;
+
+            // skip duplicate scales
+            SORTEDSCALES::iterator iter = sortedScales.find(scale);
+            if (iter != sortedScales.end())
+                continue;
+
+            // insert the scale (automatically sorted in ascending order)
+            sortedScales.insert(SORTEDSCALES::value_type(scale, scale));
+        }
+    }
+
+    // load the sorted scales into the vector
+    for (SORTEDSCALES::iterator sIter = sortedScales.begin(); sIter != sortedScales.end(); ++sIter)
+        m_finiteDisplayScales.push_back(sIter->second);
+
+    m_trackChangesDisabled = false;
+
+    // there's nothing to unpack anymore in this case
+    m_unpackedLayersGroups = true;
+
+    MG_CATCH_AND_THROW(L"MgMap.CreateFromTileSet")
 }
 
 //////////////////////////////////////////////////////////////

Modified: sandbox/jng/tiling/Common/MapGuideCommon/MapLayer/Map.h
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/MapLayer/Map.h	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Common/MapGuideCommon/MapLayer/Map.h	2014-06-02 22:33:06 UTC (rev 8180)
@@ -664,6 +664,8 @@
     static const INT32 m_cls_id = MapGuide_MapLayer_Map;
 
 private:
+    void CreateFromMapDefinition(MgResourceService* resourceService, MgResourceIdentifier* resource, CREFSTRING mapName);
+    void CreateFromTileSet(MgResourceService* resourceService, MgResourceIdentifier* resource, CREFSTRING mapName);
 
     // Version for serialization
     static const int m_serializeVersion = (4<<16) + 0;

Modified: sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.cpp
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.cpp	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.cpp	2014-06-02 22:33:06 UTC (rev 8180)
@@ -29,3 +29,4 @@
 INT32  MgTileParameters::tileHeight = 300;                    // height for all tiles
 const INT32  MgTileParameters::tileDPI    =  96;              // assumed DPI for all tiles
 STRING MgTileParameters::tileFormat = MgImageFormats::Png;    // image format for all tiles
+STRING MgTileParameters::tileCachePath = L"";                 // tile cache root directory

Modified: sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.h
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.h	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Common/MapGuideCommon/Services/TileDefs.h	2014-06-02 22:33:06 UTC (rev 8180)
@@ -43,7 +43,7 @@
 /// \cond INTERNAL
 ///////////////////////////////////////////////////////////////////////////////
 /// \brief
-/// Tile parameters.
+/// Default tile parameters.
 /// INTERNAL do not document.
 ///
 class MG_MAPGUIDE_API MgTileParameters
@@ -51,8 +51,9 @@
 INTERNAL_API:
     static INT32 tileWidth;       // width for all tiles
     static INT32 tileHeight;      // height for all tiles
-    static const INT32 tileDPI;         // assumed DPI for all tiles
+    static const INT32 tileDPI;   // assumed DPI for all tiles
     static STRING tileFormat;     // image format for all tiles
+    static STRING tileCachePath;  // tile cache root path
 };
 /// \endcond
 

Modified: sandbox/jng/tiling/Common/MapGuideCommon/System/MapGuideCommonClassId.h
===================================================================
--- sandbox/jng/tiling/Common/MapGuideCommon/System/MapGuideCommonClassId.h	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Common/MapGuideCommon/System/MapGuideCommonClassId.h	2014-06-02 22:33:06 UTC (rev 8180)
@@ -89,6 +89,7 @@
 #define MapGuide_Exception_MgUnsupportedProviderThreadModelException    MAPGUIDE_EXCEPTION_ID+53
 #define MapGuide_Exception_MgAllProviderConnectionsUsedException        MAPGUIDE_EXCEPTION_ID+54
 #define MapGuide_Exception_MgRasterTransformationNotSupportedException  MAPGUIDE_EXCEPTION_ID+55
+#define MapGuide_Exception_MgUnknownTileProviderException               MAPGUIDE_EXCEPTION_ID+56
 
 
 // MapLayer API

Modified: sandbox/jng/tiling/Server/src/PostBuild/PostBuild.mak
===================================================================
--- sandbox/jng/tiling/Server/src/PostBuild/PostBuild.mak	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/PostBuild/PostBuild.mak	2014-06-02 22:33:06 UTC (rev 8180)
@@ -164,6 +164,8 @@
         ..\..\bin\UnitTestFiles\TEST.FeatureSource \
         ..\..\bin\UnitTestFiles\TEST.sdf \
         ..\..\bin\UnitTestFiles\UT_BaseMap.mdf \
+		..\..\bin\UnitTestFiles\UT_BaseMap.tsd \
+		..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf \
         ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf \
         ..\..\bin\UnitTestFiles\UT_Parcels.fs \
         ..\..\bin\UnitTestFiles\UT_Parcels.ldf \
@@ -433,6 +435,8 @@
         ..\..\bin\UnitTestFiles\TEST.FeatureSource \
         ..\..\bin\UnitTestFiles\TEST.sdf \
         ..\..\bin\UnitTestFiles\UT_BaseMap.mdf \
+		..\..\bin\UnitTestFiles\UT_BaseMap.tsd \
+		..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf \
         ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf \
         ..\..\bin\UnitTestFiles\UT_Parcels.fs \
         ..\..\bin\UnitTestFiles\UT_Parcels.ldf \
@@ -702,6 +706,8 @@
           ..\..\bin\UnitTestFiles\TEST.FeatureSource \
           ..\..\bin\UnitTestFiles\TEST.sdf \
           ..\..\bin\UnitTestFiles\UT_BaseMap.mdf \
+		  ..\..\bin\UnitTestFiles\UT_BaseMap.tsd \
+		  ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf \
           ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf \
           ..\..\bin\UnitTestFiles\UT_Parcels.fs \
           ..\..\bin\UnitTestFiles\UT_Parcels.ldf \
@@ -971,6 +977,8 @@
           ..\..\bin\UnitTestFiles\TEST.FeatureSource \
           ..\..\bin\UnitTestFiles\TEST.sdf \
           ..\..\bin\UnitTestFiles\UT_BaseMap.mdf \
+		  ..\..\bin\UnitTestFiles\UT_BaseMap.tsd \
+		  ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf \
           ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf \
           ..\..\bin\UnitTestFiles\UT_Parcels.fs \
           ..\..\bin\UnitTestFiles\UT_Parcels.ldf \
@@ -1113,6 +1121,8 @@
     if EXIST ..\..\bin\UnitTestFiles\TEST.FeatureSource             del /F ..\..\bin\UnitTestFiles\TEST.FeatureSource
     if EXIST ..\..\bin\UnitTestFiles\TEST.sdf                       del /F ..\..\bin\UnitTestFiles\TEST.sdf
     if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.mdf                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.mdf
+	if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.tsd                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.tsd
+	if EXIST ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf           del /F ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf        del /F ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.fs                  del /F ..\..\bin\UnitTestFiles\UT_Parcels.fs
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.ldf                 del /F ..\..\bin\UnitTestFiles\UT_Parcels.ldf
@@ -1250,6 +1260,8 @@
     if EXIST ..\..\bin\UnitTestFiles\TEST.FeatureSource             del /F ..\..\bin\UnitTestFiles\TEST.FeatureSource
     if EXIST ..\..\bin\UnitTestFiles\TEST.sdf                       del /F ..\..\bin\UnitTestFiles\TEST.sdf
     if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.mdf                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.mdf
+	if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.tsd                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.tsd
+	if EXIST ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf           del /F ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf        del /F ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.fs                  del /F ..\..\bin\UnitTestFiles\UT_Parcels.fs
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.ldf                 del /F ..\..\bin\UnitTestFiles\UT_Parcels.ldf
@@ -1387,6 +1399,8 @@
     if EXIST ..\..\bin\UnitTestFiles\TEST.FeatureSource             del /F ..\..\bin\UnitTestFiles\TEST.FeatureSource
     if EXIST ..\..\bin\UnitTestFiles\TEST.sdf                       del /F ..\..\bin\UnitTestFiles\TEST.sdf
     if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.mdf                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.mdf
+	if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.tsd                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.tsd
+	if EXIST ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf           del /F ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf        del /F ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.fs                  del /F ..\..\bin\UnitTestFiles\UT_Parcels.fs
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.ldf                 del /F ..\..\bin\UnitTestFiles\UT_Parcels.ldf
@@ -1522,6 +1536,8 @@
     if EXIST ..\..\bin\UnitTestFiles\TEST.FeatureSource             del /F ..\..\bin\UnitTestFiles\TEST.FeatureSource
     if EXIST ..\..\bin\UnitTestFiles\TEST.sdf                       del /F ..\..\bin\UnitTestFiles\TEST.sdf
     if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.mdf                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.mdf
+	if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.tsd                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.tsd
+	if EXIST ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf           del /F ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf        del /F ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.fs                  del /F ..\..\bin\UnitTestFiles\UT_Parcels.fs
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.ldf                 del /F ..\..\bin\UnitTestFiles\UT_Parcels.ldf
@@ -1784,6 +1800,8 @@
         ..\..\bin\UnitTestFiles\TEST.FeatureSource \
         ..\..\bin\UnitTestFiles\TEST.sdf \
         ..\..\bin\UnitTestFiles\UT_BaseMap.mdf \
+		..\..\bin\UnitTestFiles\UT_BaseMap.tsd \
+		..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf \
         ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf \
         ..\..\bin\UnitTestFiles\UT_Parcels.fs \
         ..\..\bin\UnitTestFiles\UT_Parcels.ldf \
@@ -2046,6 +2064,8 @@
         ..\..\bin\UnitTestFiles\TEST.FeatureSource \
         ..\..\bin\UnitTestFiles\TEST.sdf \
         ..\..\bin\UnitTestFiles\UT_BaseMap.mdf \
+		..\..\bin\UnitTestFiles\UT_BaseMap.tsd \
+		..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf \
         ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf \
         ..\..\bin\UnitTestFiles\UT_Parcels.fs \
         ..\..\bin\UnitTestFiles\UT_Parcels.ldf \
@@ -2308,6 +2328,8 @@
           ..\..\bin\UnitTestFiles\TEST.FeatureSource \
           ..\..\bin\UnitTestFiles\TEST.sdf \
           ..\..\bin\UnitTestFiles\UT_BaseMap.mdf \
+		  ..\..\bin\UnitTestFiles\UT_BaseMap.tsd \
+		  ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf \
           ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf \
           ..\..\bin\UnitTestFiles\UT_Parcels.fs \
           ..\..\bin\UnitTestFiles\UT_Parcels.ldf \
@@ -2570,6 +2592,8 @@
           ..\..\bin\UnitTestFiles\TEST.FeatureSource \
           ..\..\bin\UnitTestFiles\TEST.sdf \
           ..\..\bin\UnitTestFiles\UT_BaseMap.mdf \
+		  ..\..\bin\UnitTestFiles\UT_BaseMap.tsd \
+		  ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf \
           ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf \
           ..\..\bin\UnitTestFiles\UT_Parcels.fs \
           ..\..\bin\UnitTestFiles\UT_Parcels.ldf \
@@ -2705,6 +2729,8 @@
     if EXIST ..\..\bin\UnitTestFiles\TEST.FeatureSource             del /F ..\..\bin\UnitTestFiles\TEST.FeatureSource
     if EXIST ..\..\bin\UnitTestFiles\TEST.sdf                       del /F ..\..\bin\UnitTestFiles\TEST.sdf
     if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.mdf                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.mdf
+	if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.tsd                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.tsd
+	if EXIST ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf           del /F ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf        del /F ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.fs                  del /F ..\..\bin\UnitTestFiles\UT_Parcels.fs
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.ldf                 del /F ..\..\bin\UnitTestFiles\UT_Parcels.ldf
@@ -2835,6 +2861,8 @@
     if EXIST ..\..\bin\UnitTestFiles\TEST.FeatureSource             del /F ..\..\bin\UnitTestFiles\TEST.FeatureSource
     if EXIST ..\..\bin\UnitTestFiles\TEST.sdf                       del /F ..\..\bin\UnitTestFiles\TEST.sdf
     if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.mdf                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.mdf
+	if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.tsd                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.tsd
+	if EXIST ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf           del /F ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf        del /F ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.fs                  del /F ..\..\bin\UnitTestFiles\UT_Parcels.fs
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.ldf                 del /F ..\..\bin\UnitTestFiles\UT_Parcels.ldf
@@ -2965,6 +2993,8 @@
     if EXIST ..\..\bin\UnitTestFiles\TEST.FeatureSource             del /F ..\..\bin\UnitTestFiles\TEST.FeatureSource
     if EXIST ..\..\bin\UnitTestFiles\TEST.sdf                       del /F ..\..\bin\UnitTestFiles\TEST.sdf
     if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.mdf                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.mdf
+	if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.tsd                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.tsd
+	if EXIST ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf           del /F ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf        del /F ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.fs                  del /F ..\..\bin\UnitTestFiles\UT_Parcels.fs
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.ldf                 del /F ..\..\bin\UnitTestFiles\UT_Parcels.ldf
@@ -3093,6 +3123,8 @@
     if EXIST ..\..\bin\UnitTestFiles\TEST.FeatureSource             del /F ..\..\bin\UnitTestFiles\TEST.FeatureSource
     if EXIST ..\..\bin\UnitTestFiles\TEST.sdf                       del /F ..\..\bin\UnitTestFiles\TEST.sdf
     if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.mdf                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.mdf
+	if EXIST ..\..\bin\UnitTestFiles\UT_BaseMap.tsd                 del /F ..\..\bin\UnitTestFiles\UT_BaseMap.tsd
+	if EXIST ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf           del /F ..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf        del /F ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.fs                  del /F ..\..\bin\UnitTestFiles\UT_Parcels.fs
     if EXIST ..\..\bin\UnitTestFiles\UT_Parcels.ldf                 del /F ..\..\bin\UnitTestFiles\UT_Parcels.ldf
@@ -3228,6 +3260,8 @@
 "..\..\..\UnitTestFiles\UT_SingleFTSMultiCTS.ldf" :
 "..\..\..\UnitTest\TestData\MappingService\UT_RotatedPointStyles.ldf" :
 "..\..\..\UnitTest\TestData\TileService\UT_BaseMap.mdf" :
+"..\..\..\UnitTest\TestData\TileService\UT_BaseMap.tsd" :
+"..\..\..\UnitTest\TestData\TileService\UT_LinkedTileSet.mdf" :
 "..\..\..\UnitTest\TestData\TileService\UT_StylizationFuncs.mdf" :
 "..\..\..\UnitTest\TestData\TileService\UT_Parcels.fs" :
 "..\..\..\UnitTest\TestData\TileService\UT_Parcels.ldf" :
@@ -3467,6 +3501,14 @@
     if NOT EXIST ..\..\bin\UnitTestFiles\nul mkdir ..\..\bin\UnitTestFiles
     if EXIST "..\..\..\UnitTest\TestData\TileService\UT_BaseMap.mdf" xcopy /r /d /y "..\..\..\UnitTest\TestData\TileService\UT_BaseMap.mdf" ..\..\bin\UnitTestFiles\
 
+..\..\bin\UnitTestFiles\UT_BaseMap.tsd : "..\..\..\UnitTest\TestData\TileService\UT_BaseMap.tsd"
+    if NOT EXIST ..\..\bin\UnitTestFiles\nul mkdir ..\..\bin\UnitTestFiles
+    if EXIST "..\..\..\UnitTest\TestData\TileService\UT_BaseMap.tsd" xcopy /r /d /y "..\..\..\UnitTest\TestData\TileService\UT_BaseMap.tsd" ..\..\bin\UnitTestFiles\
+
+..\..\bin\UnitTestFiles\UT_LinkedTileSet.mdf : "..\..\..\UnitTest\TestData\TileService\UT_LinkedTileSet.mdf"
+    if NOT EXIST ..\..\bin\UnitTestFiles\nul mkdir ..\..\bin\UnitTestFiles
+    if EXIST "..\..\..\UnitTest\TestData\TileService\UT_LinkedTileSet.mdf" xcopy /r /d /y "..\..\..\UnitTest\TestData\TileService\UT_LinkedTileSet.mdf" ..\..\bin\UnitTestFiles\
+
 ..\..\bin\UnitTestFiles\UT_StylizationFuncs.mdf : "..\..\..\UnitTest\TestData\TileService\UT_StylizationFuncs.mdf"
     if NOT EXIST ..\..\bin\UnitTestFiles\nul mkdir ..\..\bin\UnitTestFiles
     if EXIST "..\..\..\UnitTest\TestData\TileService\UT_StylizationFuncs.mdf" xcopy /r /d /y "..\..\..\UnitTest\TestData\TileService\UT_StylizationFuncs.mdf" ..\..\bin\UnitTestFiles\

Modified: sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.cpp
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.cpp	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.cpp	2014-06-02 22:33:06 UTC (rev 8180)
@@ -17,9 +17,15 @@
 
 #include "MapGuideCommon.h"
 #include "ServerTileService.h"
+#include "TileSetDefinition.h"
+#include "UnmanagedDataManager.h"
+#include "SAX2Parser.h"
 
 IMPLEMENT_CREATE_SERVICE(MgServerTileService)
 
+#define TILE_PROVIDER_DEFAULT L"Default"
+#define TILE_PROVIDER_DEFAULT_PARAM_TILEPATH L"TilePath"
+
 MgServerTileService::MgServerTileService() : MgTileService()
 {
     MgTileCacheDefault::Initialize();
@@ -190,7 +196,49 @@
     }
     else if (resource->GetResourceType() == MgResourceType::TileSetDefinition)
     {
+        // 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(resource, MgResourcePermission::ReadOnly))
+        {
+            MG_LOG_AUTHENTICATION_ENTRY(MgResources::PermissionDenied.c_str());
+
+            MgStringCollection arguments;
+            arguments.Add(resource->ToString());
+
+            throw new MgPermissionDeniedException(L"MgServerTileService.GetTileCache", __LINE__, __WFILE__, &arguments, L"", NULL);
+        }
+
+        Ptr<MgByteReader> content = resourceService->GetResourceContent(resource);
+        Ptr<MgByteSink> sink = new MgByteSink(content);
+        std::string xml;
+        sink->ToStringUtf8(xml);
+
+        // Before parsing, do any substitutions on the content
+        MgUnmanagedDataManager::SubstituteDataPathAliases(xml);
+
+        // parse the tile set definition
+        MdfParser::SAX2Parser parser;
+        parser.ParseString(xml.c_str(), xml.size());
+
+        if (!parser.GetSucceeded())
+        {
+            STRING errorMsg = parser.GetErrorMessage();
+            MgStringCollection arguments;
+            arguments.Add(errorMsg);
+            throw new MgXmlParserException(L"MgServerTileService.GetTileCache", __LINE__, __WFILE__, &arguments, L"", NULL);
+        }
+
+        MdfModel::TileSetDefinition* tileset = parser.DetachTileSetDefinition();
+        assert(NULL != tileset);
+        
+        cache = GetTileCache(resource, tileset);
     }
 
     MG_CATCH_AND_THROW(L"MgServerTileService.GetTileCache")
@@ -198,6 +246,47 @@
     return cache.Detach();
 }
 
+MgTileCache* MgServerTileService::GetTileCache(MgResourceIdentifier* tileSetId, MdfModel::TileSetDefinition* tileset)
+{
+    Ptr<MgTileCache> cache;
+
+    MG_TRY()
+
+    MdfModel::TileStoreParameters* tilesetParams = tileset->GetTileStoreParameters();
+    const MdfModel::MdfString& provider = tilesetParams->GetTileProvider();
+    if (provider == TILE_PROVIDER_DEFAULT)
+    {
+        MdfModel::NameStringPairCollection* parameters = tilesetParams->GetParameters();
+        STRING path;
+        for (INT32 i = 0; i < parameters->GetCount(); i++)
+        {
+            MdfModel::NameStringPair* pair = parameters->GetAt(i);
+            if (pair->GetName() == TILE_PROVIDER_DEFAULT_PARAM_TILEPATH)
+            {
+                path = pair->GetValue();
+            }
+        }
+
+        //If we find the cache path substitution tag, replace it with the default path from the configuration
+        if (path == MgResourceTag::TileCachePath)
+        {
+            path = MgTileParameters::tileCachePath;
+        }
+
+        cache = new MgTileCacheDefaultProvider(tileSetId, path, tilesetParams->GetTileWidth(), tilesetParams->GetTileHeight(), tilesetParams->GetFormat());
+    }
+    else 
+    {
+        MgStringCollection arguments;
+        arguments.Add(provider);
+        throw new MgUnknownTileProviderException(L"MgServerTileService.GetTileCache", __LINE__, __WFILE__, &arguments, L"UnknownTileProvider", NULL);
+    }
+
+    MG_CATCH_AND_THROW(L"MgServerTileService.GetTileCache")
+
+    return cache.Detach();
+}
+
 bool MgServerTileService::IsTileCacheEmpty() const
 {
     return false;

Modified: sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.h
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.h	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.h	2014-06-02 22:33:06 UTC (rev 8180)
@@ -21,6 +21,11 @@
 #include "ServerTileDllExport.h"
 #include "TileCache.h"
 
+namespace MdfModel
+{
+    class TileSetDefinition;
+}
+
 class MG_SERVER_TILE_API MgServerTileService : public MgTileService
 {
     DECLARE_CLASSNAME(MgServerTileService)
@@ -72,6 +77,7 @@
 
 private:
     MgTileCache* GetTileCache(MgResourceIdentifier* resource);
+    MgTileCache* GetTileCache(MgResourceIdentifier* tileSetId, MdfModel::TileSetDefinition* tileset);
 };
 
 #endif

Modified: sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj	2014-06-02 22:33:06 UTC (rev 8180)
@@ -94,7 +94,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\Mapping;..\..\..\..\Oem\ACE\ACE_wrappers;..\..\..\..\Oem\FDO\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\..\..\Common\MdfParser;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\Mapping;..\..\..\..\Oem\ACE\ACE_wrappers;..\..\..\..\Oem\FDO\inc;..\..\..\..\Oem\dbxml\xerces-c-src\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MG_SERVER_TILE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ExceptionHandling>Async</ExceptionHandling>
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
@@ -104,9 +104,9 @@
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
-      <AdditionalDependencies>ACEd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>ACEd.lib;MgMdfModeld.lib;MgMdfParserd.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <OutputFile>$(OutDir)MgServerTileServiced.dll</OutputFile>
-      <AdditionalLibraryDirectories>..\..\..\..\Oem\ACE\ACE_wrappers\lib\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>..\..\..\..\Oem\ACE\ACE_wrappers\lib\$(Configuration);..\..\..\..\Common\lib\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <ProgramDatabaseFile>$(OutDir)MgServerTileServiced.pdb</ProgramDatabaseFile>
       <SubSystem>Windows</SubSystem>
@@ -120,7 +120,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\Mapping;..\..\..\..\Oem\ACE\ACE_wrappers;..\..\..\..\Oem\FDO\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\..\..\Common\MdfParser;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\Mapping;..\..\..\..\Oem\ACE\ACE_wrappers;..\..\..\..\Oem\FDO\inc;..\..\..\..\Oem\dbxml\xerces-c-src\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MG_SERVER_TILE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ExceptionHandling>Async</ExceptionHandling>
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
@@ -130,9 +130,9 @@
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
-      <AdditionalDependencies>ACEd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>ACEd.lib;MgMdfModeld.lib;MgMdfParserd.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <OutputFile>$(OutDir)MgServerTileServiced.dll</OutputFile>
-      <AdditionalLibraryDirectories>..\..\..\..\Oem\ACE\ACE_wrappers\lib64\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>..\..\..\..\Oem\ACE\ACE_wrappers\lib64\$(Configuration);..\..\..\..\Common\lib\Debug64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <ProgramDatabaseFile>$(OutDir)MgServerTileServiced.pdb</ProgramDatabaseFile>
       <SubSystem>Windows</SubSystem>
@@ -146,7 +146,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <ClCompile>
       <Optimization>MaxSpeed</Optimization>
-      <AdditionalIncludeDirectories>..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\Mapping;..\..\..\..\Oem\ACE\ACE_wrappers;..\..\..\..\Oem\FDO\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\..\..\Common\MdfParser;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\Mapping;..\..\..\..\Oem\ACE\ACE_wrappers;..\..\..\..\Oem\FDO\inc;..\..\..\..\Oem\dbxml\xerces-c-src\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MG_SERVER_TILE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ExceptionHandling>Async</ExceptionHandling>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@@ -155,9 +155,9 @@
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
-      <AdditionalDependencies>ACE.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>ACE.lib;MgMdfModel.lib;MgMdfParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <OutputFile>$(OutDir)MgServerTileService.dll</OutputFile>
-      <AdditionalLibraryDirectories>..\..\..\..\Oem\ACE\ACE_wrappers\lib\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>..\..\..\..\Oem\ACE\ACE_wrappers\lib\$(Configuration);..\..\..\..\Common\lib\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <ProgramDatabaseFile>$(OutDir)MgServerTileService.pdb</ProgramDatabaseFile>
       <SubSystem>Windows</SubSystem>
@@ -173,7 +173,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <ClCompile>
       <Optimization>MaxSpeed</Optimization>
-      <AdditionalIncludeDirectories>..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\Mapping;..\..\..\..\Oem\ACE\ACE_wrappers;..\..\..\..\Oem\FDO\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\..\..\Common\MdfParser;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\Mapping;..\..\..\..\Oem\ACE\ACE_wrappers;..\..\..\..\Oem\FDO\inc;..\..\..\..\Oem\dbxml\xerces-c-src\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MG_SERVER_TILE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ExceptionHandling>Async</ExceptionHandling>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@@ -182,9 +182,9 @@
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
-      <AdditionalDependencies>ACE.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>ACE.lib;MgMdfModel.lib;MgMdfParser.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <OutputFile>$(OutDir)MgServerTileService.dll</OutputFile>
-      <AdditionalLibraryDirectories>..\..\..\..\Oem\ACE\ACE_wrappers\lib64\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>..\..\..\..\Oem\ACE\ACE_wrappers\lib64\$(Configuration);..\..\..\..\Common\lib\Release64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <ProgramDatabaseFile>$(OutDir)MgServerTileService.pdb</ProgramDatabaseFile>
       <SubSystem>Windows</SubSystem>
@@ -234,6 +234,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="TileCacheDefaultProvider.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>
@@ -279,6 +285,7 @@
     <ClInclude Include="OpGetTile.h" />
     <ClInclude Include="OpSetTile.h" />
     <ClInclude Include="TileCacheDefault.h" />
+    <ClInclude Include="TileCacheDefaultProvider.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-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/Services/Tile/ServerTileService.vcxproj.filters	2014-06-02 22:33:06 UTC (rev 8180)
@@ -33,6 +33,7 @@
     <ClCompile Include="TileCache.cpp" />
     <ClCompile Include="TileServiceHandler.cpp" />
     <ClCompile Include="TileCacheDefault.cpp" />
+    <ClCompile Include="TileCacheDefaultProvider.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="OpClearCache.h">
@@ -62,6 +63,7 @@
     <ClInclude Include="TileCache.h" />
     <ClInclude Include="TileServiceHandler.h" />
     <ClInclude Include="TileCacheDefault.h" />
+    <ClInclude Include="TileCacheDefaultProvider.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-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/Services/Tile/ServerTileServiceBuild.cpp	2014-06-02 22:33:06 UTC (rev 8180)
@@ -25,6 +25,7 @@
 #include "OpGetDefaultTileSizeY.cpp"
 #include "TileCache.cpp"
 #include "TileCacheDefault.cpp"
+#include "TileCacheDefaultProvider.cpp"
 #include "TileOperation.cpp"
 #include "TileOperationFactory.cpp"
 #include "TileServiceHandler.cpp"

Modified: sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.cpp
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.cpp	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.cpp	2014-06-02 22:33:06 UTC (rev 8180)
@@ -35,6 +35,12 @@
 INT32 MgTileCacheDefault::sm_pollingInterval = 1;          // in seconds
 INT32 MgTileCacheDefault::sm_mapCacheSize = 10;
 
+MgTileCacheDefault::MgTileCacheDefault()
+{
+    m_map = NULL;
+    m_resourceId = NULL;
+}
+
 MgTileCacheDefault::MgTileCacheDefault(MgMap* map)
 {
     m_map = SAFE_ADDREF(map);
@@ -101,6 +107,8 @@
                 // create directory if it is not already there
                 MgFileUtil::CreateDirectory(sm_path, false, true);
 
+                MgTileParameters::tileCachePath = sm_path;
+
                 configuration->GetIntValue(MgConfigProperties::TileServicePropertiesSection,
                     MgConfigProperties::TileServicePropertyTileColumnsPerFolder,
                     sm_tileColumnsPerFolder,
@@ -154,17 +162,18 @@
     if (m_map != NULL)
         ret = GetTileForMap(baseMapLayerGroupName, tileColumn, tileRow, scaleIndex);
     else if (m_resourceId != NULL)
-        ret = GetTileForMapDefinition(baseMapLayerGroupName, tileColumn, tileRow, scaleIndex);
+        ret = GetTileForResource(m_resourceId, 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)
+MgByteReader* MgTileCacheDefault::GetTileForResource(MgResourceIdentifier* resource,
+                                                     CREFSTRING baseMapLayerGroupName,
+                                                     INT32 tileColumn,
+                                                     INT32 tileRow,
+                                                     INT32 scaleIndex)
 {
     Ptr<MgByteReader> ret;
     FILE* lockFile = NULL;
@@ -172,9 +181,9 @@
 
     MG_TRY()
 
-    if (NULL == (MgResourceIdentifier*)m_resourceId || baseMapLayerGroupName.empty())
+    if (NULL == (MgResourceIdentifier*)resource || baseMapLayerGroupName.empty())
     {
-        throw new MgNullArgumentException(L"MgTileCacheDefault.GetTileForMapDefinition",
+        throw new MgNullArgumentException(L"MgTileCacheDefault.GetTileForResource",
             __LINE__, __WFILE__, NULL, L"", NULL);
     }
 
@@ -187,15 +196,15 @@
         arguments.Add(L"5");
         arguments.Add(buffer);
 
-        throw new MgInvalidArgumentException(L"MgTileCacheDefault.GetTileForMapDefinition",
+        throw new MgInvalidArgumentException(L"MgTileCacheDefault.GetTileForResource",
             __LINE__, __WFILE__, &arguments, L"MgInvalidScaleIndex", NULL);
     }
 
     // get the service from our helper method
-    Ptr<MgResourceService> resourceService = GetResourceServiceForMapDef(m_resourceId,
-                                            L"MgTileCacheDefault.GetTileForMapDefinition");
+    Ptr<MgResourceService> resourceService = GetResourceServiceForMapDef(resource,
+                                            L"MgTileCacheDefault.GetTileForResource");
     // Generate tile and lock pathnames.
-    GeneratePathNames(m_resourceId, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow, tilePathname, lockPathname, false);
+    GeneratePathNames(scaleIndex, baseMapLayerGroupName, tileColumn, tileRow, tilePathname, lockPathname, false);
 
     // If there is a dangling lock file, then attempt to remove it.
     if (DetectTileLockFile(lockPathname))
@@ -213,7 +222,7 @@
     {
         // Attempt use a cached & serialized MgMap object
         Ptr<MgMemoryStreamHelper> cachedMap;
-        STRING mapString = m_resourceId->ToString();
+        STRING mapString = resource->ToString();
         Ptr<MgMap> map;
 
         // Protect the serialized MgMap cache with a mutex.  Stream reading is not
@@ -230,7 +239,7 @@
                 MgStringCollection arguments;
                 arguments.Add(lockPathname);
 
-                throw new MgFileIoException(L"MgTileCacheDefault.GetTileForMapDefinition",
+                throw new MgFileIoException(L"MgTileCacheDefault.GetTileForResource",
                     __LINE__, __WFILE__, &arguments, L"MgUnableToLockTileFile", NULL);
             }
 
@@ -243,7 +252,7 @@
             }
 
             // Create the lock file and close it right away.
-            CreateFullPath(m_resourceId, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
+            CreateFullPath(scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
             lockFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(lockPathname), ACE_TEXT("wb"));
 
             if (NULL == lockFile)
@@ -251,7 +260,7 @@
                 MgStringCollection arguments;
                 arguments.Add(lockPathname);
 
-                throw new MgFileIoException(L"MgTileCacheDefault.GetTileForMapDefinition",
+                throw new MgFileIoException(L"MgTileCacheDefault.GetTileForResource",
                     __LINE__, __WFILE__, &arguments, L"MgUnableToOpenLockFile", NULL);
             }
             else
@@ -274,7 +283,7 @@
                 Ptr<MgUserInformation> userInfo = MgUserInformation::GetCurrentUserInfo();
                 siteConn->Open(userInfo);
                 map = new MgMap(siteConn);
-                map->Create(resourceService, m_resourceId, mapString);
+                map->Create(resourceService, resource, mapString);
                 cachedMap = new MgMemoryStreamHelper();
                 Ptr<MgStream> stream = new MgStream(cachedMap);
                 map->Serialize(stream);
@@ -294,7 +303,7 @@
         break;
     }
 
-    MG_CATCH(L"MgTileCacheDefault.GetTileForMapDefinition")
+    MG_CATCH(L"MgTileCacheDefault.GetTileForResource")
 
     if (NULL != lockFile)
     {
@@ -335,7 +344,7 @@
     }
 
     // Detect the lock file to see if another thread is creating the tile file.
-    GeneratePathNames(m_map, scaleIndex, baseMapLayerGroupName,
+    GeneratePathNames(scaleIndex, baseMapLayerGroupName,
         tileColumn, tileRow, tilePathname, lockPathname, false);
 
     // If there is a dangling lock file, then attempt to remove it.
@@ -375,7 +384,7 @@
             }
 
             // Create the lock file and close it right away.
-            CreateFullPath(m_map, scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
+            CreateFullPath(scaleIndex, baseMapLayerGroupName, tileColumn, tileRow);
             lockFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(lockPathname), ACE_TEXT("wb"));
 
             if (NULL == lockFile)
@@ -426,7 +435,7 @@
     if (svcRendering != NULL)
     {
         // generate the tile
-        img = svcRendering->RenderTile(map, baseMapLayerGroupName, tileColumn, tileRow);
+        img = svcRendering->RenderTile(map, baseMapLayerGroupName, tileColumn, tileRow, GetDefaultTileSizeX(), GetDefaultTileSizeY(), map->GetDisplayDpi(), GetTileFormat());
 
         // cache the tile
         if (!sm_renderOnly)
@@ -475,7 +484,7 @@
     }
 
     // Generate tile and lock pathnames.
-    GeneratePathNames(m_map, scaleIndex, baseMapLayerGroupName,
+    GeneratePathNames(scaleIndex, baseMapLayerGroupName,
         tileColumn, tileRow, tilePathname, lockPathname, true);
 
     {
@@ -520,23 +529,11 @@
 
 void MgTileCacheDefault::Clear()
 {
-    if (m_map != NULL)
-    {
-        STRING basePath = GetBasePath(m_map);
+    STRING basePath = GetBasePath();
 
-        // 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);
-    }
+    // delete main map directory
+    if (!basePath.empty())
+        MgFileUtil::DeleteDirectory(basePath, true, false);
 }
 
 INT32 MgTileCacheDefault::GetDefaultTileSizeX()
@@ -549,6 +546,11 @@
     return MgTileParameters::tileHeight;
 }
 
+STRING MgTileCacheDefault::GetTileFormat()
+{
+    return MgTileParameters::tileFormat;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // accessor method for resource service
 MgResourceService* MgTileCacheDefault::GetResourceServiceForMapDef(MgResourceIdentifier* mapDefinition,
@@ -643,27 +645,16 @@
     }
 }
 
-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,
+void MgTileCacheDefault::GeneratePathNames(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);
+    STRING basePath = GetBasePath();
 
     if (createFullPath)
     {
@@ -679,11 +670,12 @@
     //     <lockPathname> = <fullPath>/<row>_<column>.lck
     tilePathname += fileName;
     lockPathname = tilePathname;
-    if (MgTileParameters::tileFormat == MgImageFormats::Jpeg)
+    STRING fmt = GetTileFormat();
+    if (fmt == MgImageFormats::Jpeg)
     {
         tilePathname += L"jpg";
     }
-    else if (MgTileParameters::tileFormat == MgImageFormats::Gif)
+    else if (fmt == MgImageFormats::Gif)
     {
         tilePathname += L"gif";
     }
@@ -772,45 +764,42 @@
     return fullPath;
 }
 
-STRING MgTileCacheDefault::CreateFullPath(MgResourceIdentifier* mapDef, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
+STRING MgTileCacheDefault::CreateFullPath(int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
 {
-    return CreateFullPath(GetBasePath(mapDef), scaleIndex, group, tileColumn, tileRow);
+    return CreateFullPath(GetBasePath(), scaleIndex, group, tileColumn, tileRow);
 }
 
-STRING MgTileCacheDefault::CreateFullPath(MgMap* map, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
+STRING MgTileCacheDefault::GetBasePath()
 {
-    return CreateFullPath(GetBasePath(map), scaleIndex, group, tileColumn, tileRow);
+    Ptr<MgResourceIdentifier> resId;
+    if (NULL != (MgMap*)m_map)
+    {
+        resId = m_map->GetMapDefinition();
+    }
+    else if (NULL != m_resourceId && m_resourceId->GetResourceType() == MgResourceType::MapDefinition)
+    {
+        resId = SAFE_ADDREF((MgResourceIdentifier*)m_resourceId);
+    }
+    return GetBasePathFromResourceId(resId);
 }
 
-// gets the base path to use with the tile cache for the given map
-STRING MgTileCacheDefault::GetBasePath(MgMap* map)
+STRING MgTileCacheDefault::GetBasePathFromResourceId(MgResourceIdentifier* resId)
 {
-    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)
+    if (resId->GetRepositoryType() == MgRepositoryType::Library)
     {
         // for maps in the library repository the path+name is unique
-        mapPath  = mapDef->GetPath();
+        mapPath  = resId->GetPath();
         mapPath += L"_";
-        mapPath += mapDef->GetName();
+        mapPath += resId->GetName();
     }
-    else if (mapDef->GetRepositoryType() == MgRepositoryType::Session)
+    else if (resId->GetRepositoryType() == MgRepositoryType::Session)
     {
         // for maps in the session repository we use the session + path + map name
-        mapPath  = mapDef->GetRepositoryName();
+        mapPath  = resId->GetRepositoryName();
         mapPath += L"_";
 
-        STRING resourcePath  = mapDef->GetPath();
+        STRING resourcePath  = resId->GetPath();
 
         if (!resourcePath.empty())
         {
@@ -818,7 +807,7 @@
             mapPath += L"_";
         }
 
-        mapPath += mapDef->GetName();
+        mapPath += resId->GetName();
     }
     else
     {
@@ -863,19 +852,11 @@
 }
 
 // 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)
+STRING MgTileCacheDefault::GetFullPath(int scaleIndex, CREFSTRING group, int tileColumn, int tileRow)
 {
-    return GetFullPath(GetBasePath(mapDef), scaleIndex, group, tileColumn, tileRow);
+    return GetFullPath(GetBasePath(), 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)
 {

Modified: sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.h
===================================================================
--- sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.h	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/Services/Tile/TileCacheDefault.h	2014-06-02 22:33:06 UTC (rev 8180)
@@ -19,9 +19,11 @@
 
 #include "TileCache.h"
 
+//The default tile cache implementation with default settings based on server configuration
 class MG_SERVER_TILE_API MgTileCacheDefault : public MgTileCache
 {
 public:
+    MgTileCacheDefault();
     MgTileCacheDefault(MgMap* map);
     MgTileCacheDefault(MgResourceIdentifier* resource);
     virtual ~MgTileCacheDefault();
@@ -45,6 +47,8 @@
 
     virtual INT32 GetDefaultTileSizeY();
 
+    virtual STRING GetTileFormat();
+
     void ClearMapCache(CREFSTRING mapName);
 
 protected:
@@ -53,12 +57,17 @@
         delete this;
     }
 
+    virtual STRING GetBasePath();
+    virtual STRING GetFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
+    virtual STRING CreateFullPath(CREFSTRING basePath, int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
+
+    MgByteReader* GetTileForResource(MgResourceIdentifier* resource,
+                                     CREFSTRING baseMapLayerGroupName,
+                                     INT32 tileColumn,
+                                     INT32 tileRow,
+                                     INT32 scaleIndex);
+
 private:
-    MgByteReader* GetTileForMapDefinition(CREFSTRING baseMapLayerGroupName,
-                                          INT32 tileColumn,
-                                          INT32 tileRow,
-                                          INT32 scaleIndex);
-
     MgByteReader* GetTileForMap(CREFSTRING baseMapLayerGroupName,
                                 INT32 tileColumn,
                                 INT32 tileRow,
@@ -69,23 +78,15 @@
     void Set(MgByteReader* img, CREFSTRING path);
     MgByteReader* Get(CREFSTRING path);
 
-    void GeneratePathNames(MgResourceIdentifier* mapDef, int scaleIndex,
+    void GeneratePathNames(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 GetBasePathFromResourceId(MgResourceIdentifier* resId);
 
-    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 GetFullPath(int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
+    
+    STRING CreateFullPath(int scaleIndex, CREFSTRING group, int tileColumn, int tileRow);
 
     STRING GetScaleIndexFolder(int scaleIndex);
     STRING GetRowFolder(int tileRow);

Modified: sandbox/jng/tiling/Server/src/UnitTesting/TestMdfModel.cpp
===================================================================
--- sandbox/jng/tiling/Server/src/UnitTesting/TestMdfModel.cpp	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/UnitTesting/TestMdfModel.cpp	2014-06-02 22:33:06 UTC (rev 8180)
@@ -82,6 +82,11 @@
         Ptr<MgByteSource> mdfsrc4 = new MgByteSource(L"../UnitTestFiles/MdfTestMap.mdf", false);
         Ptr<MgByteReader> mdfrdr4 = mdfsrc4->GetReader();
         m_svcResource->SetResource(mdfres4, mdfrdr4, NULL);
+
+        Ptr<MgResourceIdentifier> mdfres5 = new MgResourceIdentifier(L"Library://UnitTests/MdfModel/MdfTestTileSet.TileSetDefinition");
+        Ptr<MgByteSource> mdfsrc5 = new MgByteSource(L"../UnitTestFiles/UT_BaseMap.tsd", false);
+        Ptr<MgByteReader> mdfrdr5 = mdfsrc5->GetReader();
+        m_svcResource->SetResource(mdfres5, mdfrdr5, NULL);
     }
     catch (MgException* e)
     {
@@ -114,6 +119,8 @@
         m_svcResource->DeleteResource(ldfres3);
         Ptr<MgResourceIdentifier> mdfres4 = new MgResourceIdentifier(L"Library://UnitTests/MdfModel/MdfTestMap.MapDefinition");
         m_svcResource->DeleteResource(mdfres4);
+        Ptr<MgResourceIdentifier> mdfres5 = new MgResourceIdentifier(L"Library://UnitTests/MdfModel/MdfTestTileSet.TileSetDefinition");
+        m_svcResource->DeleteResource(mdfres5);
     }
     catch(MgFileIoException* e)
     {
@@ -861,3 +868,77 @@
         CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
     }
 }
+
+void TestMdfModel::TestCase_TileSetDefinition()
+{
+    try
+    {
+        Ptr<MgResourceIdentifier> tsId = new MgResourceIdentifier(L"Library://UnitTests/MdfModel/MdfTestTileSet.TileSetDefinition");
+        Ptr<MgByteReader> content = m_svcResource->GetResourceContent(tsId);
+        Ptr<MgByteSink> sink = new MgByteSink(content);
+        Ptr<MgByte> bytes = sink->ToBuffer();
+
+        MdfParser::SAX2Parser parser;
+        parser.ParseString((const char*)bytes->Bytes(), bytes->GetLength());
+
+        CPPUNIT_ASSERT(parser.GetSucceeded());
+        MdfModel::TileSetDefinition* tileset = parser.DetachTileSetDefinition();
+        CPPUNIT_ASSERT(NULL != tileset);
+
+        MdfModel::TileStoreParameters* tilesetParams = tileset->GetTileStoreParameters();
+        CPPUNIT_ASSERT(NULL != tilesetParams);
+        CPPUNIT_ASSERT(L"Default" == tilesetParams->GetTileProvider());
+        CPPUNIT_ASSERT(256 == tilesetParams->GetTileWidth());
+        CPPUNIT_ASSERT(256 == tilesetParams->GetTileHeight());
+        CPPUNIT_ASSERT(L"PNG" == tilesetParams->GetFormat());
+
+        const MdfModel::Box2D& extents = tileset->GetExtents();
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(-87.79786601383196, extents.GetMinX(), 0.00000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL( 43.686857862181,   extents.GetMinY(), 0.000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(-87.66452777186925, extents.GetMaxX(), 0.00000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL( 43.8037962206133,  extents.GetMaxY(), 0.0000000000001);
+
+        MdfModel::DisplayScaleCollection* scales = tileset->GetFiniteDisplayScales();
+        CPPUNIT_ASSERT(10 == scales->GetCount());
+        CPPUNIT_ASSERT(200000 == scales->GetAt(0)->GetValue());
+        CPPUNIT_ASSERT(100000 == scales->GetAt(1)->GetValue());
+        CPPUNIT_ASSERT(50000 == scales->GetAt(2)->GetValue());
+        CPPUNIT_ASSERT(25000 == scales->GetAt(3)->GetValue());
+        CPPUNIT_ASSERT(12500 == scales->GetAt(4)->GetValue());
+        CPPUNIT_ASSERT(6250 == scales->GetAt(5)->GetValue());
+        CPPUNIT_ASSERT(3125 == scales->GetAt(6)->GetValue());
+        CPPUNIT_ASSERT(1562.5 == scales->GetAt(7)->GetValue());
+        CPPUNIT_ASSERT(781.25 == scales->GetAt(8)->GetValue());
+        CPPUNIT_ASSERT(390.625 == scales->GetAt(9)->GetValue());
+
+        MdfModel::BaseMapLayerGroupCollection* groups = tileset->GetBaseMapLayerGroups();
+        CPPUNIT_ASSERT(1 == groups->GetCount());
+        CPPUNIT_ASSERT(L"BaseLayers" == groups->GetAt(0)->GetName());
+        CPPUNIT_ASSERT(L"Base Layers" == groups->GetAt(0)->GetLegendLabel());
+        CPPUNIT_ASSERT(groups->GetAt(0)->IsShowInLegend());
+        CPPUNIT_ASSERT(groups->GetAt(0)->IsExpandInLegend());
+
+        MdfModel::BaseMapLayerCollection* layers = groups->GetAt(0)->GetLayers();
+        CPPUNIT_ASSERT(2 == layers->GetCount());
+
+        CPPUNIT_ASSERT(L"Parcels" == layers->GetAt(0)->GetName());
+        CPPUNIT_ASSERT(L"Parcels" == layers->GetAt(0)->GetLegendLabel());
+        CPPUNIT_ASSERT(L"Library://UnitTests/Layers/Parcels.LayerDefinition" == layers->GetAt(0)->GetLayerResourceID());
+        CPPUNIT_ASSERT(!layers->GetAt(0)->IsExpandInLegend());
+        CPPUNIT_ASSERT(layers->GetAt(0)->IsShowInLegend());
+        CPPUNIT_ASSERT(layers->GetAt(0)->IsSelectable());
+
+        CPPUNIT_ASSERT(L"VotingDistricts" == layers->GetAt(1)->GetName());
+        CPPUNIT_ASSERT(L"Voting Districts" == layers->GetAt(1)->GetLegendLabel());
+        CPPUNIT_ASSERT(L"Library://UnitTests/Layers/VotingDistricts.LayerDefinition" == layers->GetAt(1)->GetLayerResourceID());
+        CPPUNIT_ASSERT(!layers->GetAt(1)->IsExpandInLegend());
+        CPPUNIT_ASSERT(layers->GetAt(1)->IsShowInLegend());
+        CPPUNIT_ASSERT(layers->GetAt(1)->IsSelectable());
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+}

Modified: sandbox/jng/tiling/Server/src/UnitTesting/TestMdfModel.h
===================================================================
--- sandbox/jng/tiling/Server/src/UnitTesting/TestMdfModel.h	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/UnitTesting/TestMdfModel.h	2014-06-02 22:33:06 UTC (rev 8180)
@@ -28,6 +28,8 @@
     CPPUNIT_TEST(TestCase_Serialization);
     CPPUNIT_TEST(TestCase_Versioning);
 
+    CPPUNIT_TEST(TestCase_TileSetDefinition);
+
     CPPUNIT_TEST(TestEnd); // This must be the very last unit test
     CPPUNIT_TEST_SUITE_END();
 
@@ -42,6 +44,7 @@
 
     void TestCase_Serialization();
     void TestCase_Versioning();
+    void TestCase_TileSetDefinition();
 
 private:
     Ptr<MgResourceService> m_svcResource;

Modified: sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.cpp
===================================================================
--- sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.cpp	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.cpp	2014-06-02 22:33:06 UTC (rev 8180)
@@ -118,6 +118,16 @@
         Ptr<MgByteReader> mdfrdr1 = mdfsrc1->GetReader();
         m_svcResource->SetResource(mapres1, mdfrdr1, NULL);
 
+        Ptr<MgResourceIdentifier> mapres2 = new MgResourceIdentifier(L"Library://UnitTests/Maps/LinkedTileSet.MapDefinition");
+        Ptr<MgByteSource> mdfsrc2 = new MgByteSource(L"../UnitTestFiles/UT_LinkedTileSet.mdf", false);
+        Ptr<MgByteReader> mdfrdr2 = mdfsrc2->GetReader();
+        m_svcResource->SetResource(mapres2, mdfrdr2, NULL);
+
+        Ptr<MgResourceIdentifier> tilesetres1 = new MgResourceIdentifier(L"Library://UnitTests/TileSets/Sheboygan.TileSetDefinition");
+        Ptr<MgByteSource> tsdsrc1 = new MgByteSource(L"../UnitTestFiles/UT_BaseMap.tsd", false);
+        Ptr<MgByteReader> tsdrdr1 = tsdsrc1->GetReader();
+        m_svcResource->SetResource(tilesetres1, tsdrdr1, NULL);
+
         // publish the layer definitions
         Ptr<MgResourceIdentifier> ldfres1 = new MgResourceIdentifier(L"Library://UnitTests/Layers/RoadCenterLines.LayerDefinition");
         Ptr<MgByteSource> ldfsrc1 = new MgByteSource(L"../UnitTestFiles/UT_RoadCenterLines.ldf", false);
@@ -196,6 +206,12 @@
         Ptr<MgResourceIdentifier> mapres1 = new MgResourceIdentifier(L"Library://UnitTests/Maps/BaseMap.MapDefinition");
         m_svcResource->DeleteResource(mapres1);
 
+        Ptr<MgResourceIdentifier> mapres2 = new MgResourceIdentifier(L"Library://UnitTests/Maps/LinkedTileSet.MapDefinition");
+        m_svcResource->DeleteResource(mapres2);
+
+        Ptr<MgResourceIdentifier> tilesetres1 = new MgResourceIdentifier(L"Library://UnitTests/TileSets/Sheboygan.TileSetDefinition");
+        m_svcResource->DeleteResource(tilesetres1);
+
         // delete the layer definitions
         Ptr<MgResourceIdentifier> ldfres1 = new MgResourceIdentifier(L"Library://UnitTests/Layers/RoadCenterLines.LayerDefinition");
         m_svcResource->DeleteResource(ldfres1);
@@ -251,6 +267,8 @@
     Ptr<MgMap> map;
     INT32 tileRow;
     INT32 tileCol;
+    INT32 tileScale;
+    STRING tileSetId;
 };
 
 
@@ -451,7 +469,198 @@
     }
 }
 
+// the method which gets executed by the ACE worker thread
+ACE_THR_FUNC_RETURN GetTileLinkedWorker(void* param)
+{
+    // get the data for this thread
+    TileThreadData* threadData = (TileThreadData*)param;
+    INT32 threadId = threadData->threadId;
+    INT32 tileRow  = threadData->tileRow;
+    INT32 tileCol  = threadData->tileCol;
+    INT32 tileScale = threadData->tileScale;
+    bool saveTile  = threadData->saveTile;
+    Ptr<MgResourceIdentifier> tsId = new MgResourceIdentifier(threadData->tileSetId);
+    #ifdef _DEBUG
+    printf("> thread %d started, tile %d,%d\n", threadId, tileRow, tileCol);
+    #endif
 
+    try
+    {
+        // set user info
+        Ptr<MgUserInformation> userInfo = new MgUserInformation(L"Administrator", L"admin");
+        userInfo->SetLocale(TEST_LOCALE);
+        MgUserInformation::SetCurrentUserInfo(userInfo);
+
+        // get the tile service instance
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        Ptr<MgTileService> svcTile = dynamic_cast<MgTileService*>(
+            serviceManager->RequestService(MgServiceType::TileService));
+        assert(svcTile != NULL);
+
+        // get the tile
+        Ptr<MgByteReader> img = svcTile->GetTile(tsId, L"BaseLayers", tileCol, tileRow, tileScale);
+        CHECKNULL((MgByteReader*)img, L"GetTileLinkedWorker");
+
+        // save the image to a file if necessary
+        if (saveTile)
+        {
+            wchar_t imgName[PATH_LEN] = { 0 };
+            swprintf(imgName, PATH_LEN, L"./temp_tiles/tile%d_%d.png", tileRow, tileCol);
+            (MgByteSink(img)).ToFile(imgName);
+        }
+
+        // clear the user info to prevent leaks
+        MgUserInformation::SetCurrentUserInfo(NULL);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+
+    #ifdef _DEBUG
+//  printf("> thread %d done\n", threadId);
+    #endif
+
+    threadData->done = true;
+    return 0;
+}
+
+void TestTileService::TestCase_GetTileLinked()
+{
+    // specify the number of threads to use
+    const INT32 numThreads = MG_TEST_THREADS;
+    TileThreadData threadData[numThreads];
+
+    // define the range of tiles to get
+    INT32 tileRowMin =  0;
+    INT32 tileRowMax = 12;
+    INT32 tileColMin =  3;
+    INT32 tileColMax = 11;
+
+    try
+    {
+        // need a thread manager
+        ACE_Thread_Manager* manager = ACE_Thread_Manager::instance();
+
+        // make the runtime map
+        Ptr<MgMap> map = CreateMapLinked();
+        Ptr<MgResourceIdentifier> tsId;
+        Ptr<MgLayerGroupCollection> groups = map->GetLayerGroups();
+        Ptr<MgLayerGroup> group = groups->GetItem(L"BaseLayers");
+        tsId = group->GetTileSetDefinition();
+
+        // set up the tile indices
+        INT32 numTileRows = tileRowMax - tileRowMin + 1;
+        INT32 numTileCols = tileColMax - tileColMin + 1;
+        INT32 numTiles    = numTileRows * numTileCols;
+
+        INT32* tileRows = new INT32[numTiles];
+        INT32* tileCols = new INT32[numTiles];
+
+        INT32 nRequest = 0;
+        for (INT32 tileRow = tileRowMin; tileRow <= tileRowMax; ++tileRow)
+        {
+            for (INT32 tileCol = tileColMin; tileCol <= tileColMax; ++tileCol)
+            {
+                tileRows[nRequest] = tileRow;
+                tileCols[nRequest] = tileCol;
+                nRequest++;
+            }
+        }
+
+        // initialize the thread data
+        for (INT32 i=0; i<numThreads; i++)
+        {
+            // each thread works with its own instance of the map
+            threadData[i].threadId = i;
+            threadData[i].done     = true;
+            threadData[i].saveTile = false;
+            threadData[i].tileRow  = 0;
+            threadData[i].tileCol  = 0;
+            threadData[i].tileScale = 4;
+            threadData[i].tileSetId = tsId->ToString().c_str();
+        }
+
+        // execute the requests to randomly access the tiles
+        #ifdef _DEBUG
+        printf("\n");
+        #endif
+        nRequest = 0;
+        for (;;)
+        {
+            INT32 dc = 0;
+            for (INT32 i=0; i<numThreads; i++)
+            {
+                // check if the thread is available
+                if (threadData[i].done)
+                {
+                    // if we're not yet done then give the thread a new request
+                    if (nRequest < REQUEST_FACTOR*numTiles)
+                    {
+                        // pick a random request to execute...
+                        INT32 nTile = Rand(numTiles);
+
+                        // ... but make every REQUEST_FACTOR-th tile non-random to
+                        // ensure we get each tile at least once
+                        if (nRequest % REQUEST_FACTOR == 0)
+                            nTile = nRequest / REQUEST_FACTOR;
+
+                        threadData[i].done     = false;
+                        threadData[i].saveTile = (nRequest % REQUEST_FACTOR == 0);
+                        threadData[i].tileRow  = tileRows[nTile];
+                        threadData[i].tileCol  = tileCols[nTile];
+
+                        // spawn a new thread using a specific group id
+                        int thid = manager->spawn(ACE_THR_FUNC(GetTileLinkedWorker), &threadData[i], 0, NULL, NULL, 0, THREAD_GROUP);
+                        nRequest++;
+                    }
+
+                    // keep a tally of all the done threads
+                    if (threadData[i].done)
+                        ++dc;
+                }
+            }
+
+            // move on if all threads are done
+            if (dc == numThreads)
+                break;
+
+            // under Linux we get a deadlock if we don't call this every once in a while
+            if (nRequest % 25 == 0)
+                manager->wait_grp(THREAD_GROUP);
+            else
+            {
+                // pause briefly (10ms) before checking again
+                ACE_Time_Value t(0, 10000);
+                ACE_OS::sleep(t);
+            }
+        }
+
+        // make sure all threads in the group have completed
+        manager->wait_grp(THREAD_GROUP);
+
+        // done with the tile indices
+        delete [] tileRows;
+        delete [] tileCols;
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
 ////////////////////////////////////////////////////////////////
 /// SetTile methods
 ////////////////////////////////////////////////////////////////
@@ -844,7 +1053,6 @@
     }
 }
 
-
 ////////////////////////////////////////////////////////////////
 /// ClearCache methods
 ////////////////////////////////////////////////////////////////
@@ -881,6 +1089,144 @@
 }
 
 
+void TestTileService::TestCase_ClearCacheLinked()
+{
+    try
+    {
+        // call the API with a NULL argument
+        CPPUNIT_ASSERT_THROW_MG(m_svcTile->ClearCache((MgResourceIdentifier*)NULL), MgNullArgumentException*);
+
+        Ptr<MgResourceIdentifier> tsId = new MgResourceIdentifier(L"Library://UnitTests/TileSets/Sheboygan.TileSetDefinition");
+        m_svcTile->ClearCache(tsId);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+
+void TestTileService::TestCase_MgMap_Inline()
+{
+    try
+    {
+        Ptr<MgMap> map = CreateMap();
+
+        Ptr<MgEnvelope> extents = map->GetMapExtent();
+        Ptr<MgCoordinate> ll = extents->GetLowerLeftCoordinate();
+        Ptr<MgCoordinate> ur = extents->GetUpperRightCoordinate();
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(-87.79786601383196, ll->GetX(), 0.00000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL( 43.686857862181,   ll->GetY(), 0.000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(-87.66452777186925, ur->GetX(), 0.00000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL( 43.8037962206133,  ur->GetY(), 0.0000000000001);
+
+        Ptr<MgLayerGroupCollection> groups = map->GetLayerGroups();
+        for (INT32 i = 0; i < groups->GetCount(); i++)
+        {
+            Ptr<MgLayerGroup> group = groups->GetItem(i);
+            CPPUNIT_ASSERT(MgLayerGroupType::BaseMap == group->GetLayerGroupType());
+            Ptr<MgResourceIdentifier> tsId = group->GetTileSetDefinition();
+            CPPUNIT_ASSERT(NULL == (MgResourceIdentifier*)tsId);
+        }
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestTileService::TestCase_MgMap_Linked()
+{
+    try
+    {
+        Ptr<MgMap> map = CreateMapLinked();
+
+        //Bounds should be that of the tile set
+        Ptr<MgEnvelope> extents = map->GetMapExtent();
+        Ptr<MgCoordinate> ll = extents->GetLowerLeftCoordinate();
+        Ptr<MgCoordinate> ur = extents->GetUpperRightCoordinate();
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(-87.797866013831, ll->GetX(), 0.000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL( 43.686857862181, ll->GetY(), 0.000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(-87.664527771869, ur->GetX(), 0.000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL( 43.803796220613, ur->GetY(), 0.000000000001);
+
+        Ptr<MgLayerGroupCollection> groups = map->GetLayerGroups();
+        for (INT32 i = 0; i < groups->GetCount(); i++)
+        {
+            Ptr<MgLayerGroup> group = groups->GetItem(i);
+            CPPUNIT_ASSERT(MgLayerGroupType::BaseMapFromTileSet == group->GetLayerGroupType());
+            Ptr<MgResourceIdentifier> tsId = group->GetTileSetDefinition();
+            CPPUNIT_ASSERT(NULL != (MgResourceIdentifier*)tsId);
+            CPPUNIT_ASSERT(L"Library://UnitTests/TileSets/Sheboygan.TileSetDefinition" == tsId->ToString());
+        }
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestTileService::TestCase_MgMapFromTileSet()
+{
+    try
+    {
+        // make a runtime map
+        Ptr<MgResourceIdentifier> tsdres = new MgResourceIdentifier(L"Library://UnitTests/TileSets/Sheboygan.TileSetDefinition");
+        MgMap* map = new MgMap(m_siteConnection);
+        map->Create(tsdres, L"LinkedTileSet");
+
+        Ptr<MgResourceIdentifier> mdfId = map->GetMapDefinition();
+        CPPUNIT_ASSERT(NULL == (MgResourceIdentifier*)mdfId);
+
+        //Bounds should be that of the tile set
+        Ptr<MgEnvelope> extents = map->GetMapExtent();
+        Ptr<MgCoordinate> ll = extents->GetLowerLeftCoordinate();
+        Ptr<MgCoordinate> ur = extents->GetUpperRightCoordinate();
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(-87.797866013831, ll->GetX(), 0.000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL( 43.686857862181, ll->GetY(), 0.000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(-87.664527771869, ur->GetX(), 0.000000000001);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL( 43.803796220613, ur->GetY(), 0.000000000001);
+
+        Ptr<MgLayerGroupCollection> groups = map->GetLayerGroups();
+        for (INT32 i = 0; i < groups->GetCount(); i++)
+        {
+            Ptr<MgLayerGroup> group = groups->GetItem(i);
+            CPPUNIT_ASSERT(MgLayerGroupType::BaseMapFromTileSet == group->GetLayerGroupType());
+            Ptr<MgResourceIdentifier> tsId = group->GetTileSetDefinition();
+            CPPUNIT_ASSERT(NULL != (MgResourceIdentifier*)tsId);
+            CPPUNIT_ASSERT(L"Library://UnitTests/TileSets/Sheboygan.TileSetDefinition" == tsId->ToString());
+        }
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
 ////////////////////////////////////////////////////////////////
 /// Helpers
 ////////////////////////////////////////////////////////////////
@@ -911,6 +1257,30 @@
 }
 
 
+MgMap* TestTileService::CreateMapLinked(CREFSTRING mapName)
+{
+    // set a default name if not supplied
+    STRING name = (mapName.empty())? L"UnitTestBaseMapLinked" : mapName;
+
+    // make a runtime map
+    Ptr<MgResourceIdentifier> mdfres = new MgResourceIdentifier(L"Library://UnitTests/Maps/LinkedTileSet.MapDefinition");
+    MgMap* map = new MgMap(m_siteConnection);
+    map->Create(mdfres, name);
+
+    // set the view
+    Ptr<MgCoordinate> coordNewCenter = new MgCoordinateXY(-87.723636, 43.715015);
+    Ptr<MgPoint> ptNewCenter = new MgPoint(coordNewCenter);
+    map->SetViewCenter(ptNewCenter);
+    map->SetDisplayDpi(96);
+    map->SetDisplayWidth(1024);
+    map->SetDisplayHeight(1024);
+
+    // render at a scale of 1:12500
+    map->SetViewScale(12500.0);
+
+    return map;
+}
+
 // returns a random integer in the range 0 to n-1
 INT32 TestTileService::Rand(INT32 n)
 {

Modified: sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.h
===================================================================
--- sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.h	2014-06-02 20:35:11 UTC (rev 8179)
+++ sandbox/jng/tiling/Server/src/UnitTesting/TestTileService.h	2014-06-02 22:33:06 UTC (rev 8180)
@@ -29,6 +29,11 @@
     CPPUNIT_TEST(TestCase_SetTile);
     CPPUNIT_TEST(TestCase_GetSetTile);
     CPPUNIT_TEST(TestCase_ClearCache);
+    CPPUNIT_TEST(TestCase_GetTileLinked);
+    CPPUNIT_TEST(TestCase_ClearCacheLinked);
+    CPPUNIT_TEST(TestCase_MgMap_Inline);
+    CPPUNIT_TEST(TestCase_MgMap_Linked);
+    CPPUNIT_TEST(TestCase_MgMapFromTileSet);
 
     CPPUNIT_TEST(TestEnd); // This must be the very last unit test
     CPPUNIT_TEST_SUITE_END();
@@ -42,13 +47,19 @@
     void TestStart();
     void TestEnd();
 
+    void TestCase_MgMap_Inline();
+    void TestCase_MgMap_Linked();
+    void TestCase_MgMapFromTileSet();
     void TestCase_GetTile();
     void TestCase_SetTile();
     void TestCase_GetSetTile();
     void TestCase_ClearCache();
+    void TestCase_GetTileLinked();
+    void TestCase_ClearCacheLinked();
 
 private:
     MgMap* CreateMap(CREFSTRING mapName = L"");
+    MgMap* CreateMapLinked(CREFSTRING mapName = L"");
     INT32 Rand(INT32 n);
 
 private:

Added: sandbox/jng/tiling/UnitTest/TestData/TileService/UT_BaseMap.tsd
===================================================================
--- sandbox/jng/tiling/UnitTest/TestData/TileService/UT_BaseMap.tsd	                        (rev 0)
+++ sandbox/jng/tiling/UnitTest/TestData/TileService/UT_BaseMap.tsd	2014-06-02 22:33:06 UTC (rev 8180)
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<TileSetDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="TileSetDefinition-3.0.0.xsd">
+  <TileStoreParameters>
+    <TileProvider>Default</TileProvider>
+    <TileWidth>256</TileWidth>
+    <TileHeight>256</TileHeight>
+    <Format>PNG</Format>
+    <Parameter>
+      <Name>TilePath</Name>
+      <Value>%MG_TILE_CACHE_PATH%</Value>
+    </Parameter>
+  </TileStoreParameters>
+  <CoordinateSystem>GEOGCS["LL84",DATUM["WGS 84",SPHEROID["WGS 84",6378137,298.25722293287],TOWGS84[0,0,0,0,0,0,0]],PRIMEM["Greenwich",0],UNIT["Degrees",0.01745329252]]</CoordinateSystem>
+  <Extents>
+    <MinX>-87.79786601383196</MinX>
+    <MaxX>-87.66452777186925</MaxX>
+    <MinY>43.6868578621819</MinY>
+    <MaxY>43.8037962206133</MaxY>
+  </Extents>
+  <FiniteDisplayScale>200000</FiniteDisplayScale>
+  <FiniteDisplayScale>100000</FiniteDisplayScale>
+  <FiniteDisplayScale>50000</FiniteDisplayScale>
+  <FiniteDisplayScale>25000</FiniteDisplayScale>
+  <FiniteDisplayScale>12500</FiniteDisplayScale>
+  <FiniteDisplayScale>6250</FiniteDisplayScale>
+  <FiniteDisplayScale>3125</FiniteDisplayScale>
+  <FiniteDisplayScale>1562.5</FiniteDisplayScale>
+  <FiniteDisplayScale>781.25</FiniteDisplayScale>
+  <FiniteDisplayScale>390.625</FiniteDisplayScale>
+  <BaseMapLayerGroup>
+    <Name>BaseLayers</Name>
+    <Visible>true</Visible>
+    <ShowInLegend>true</ShowInLegend>
+    <ExpandInLegend>true</ExpandInLegend>
+    <LegendLabel>Base Layers</LegendLabel>
+    <BaseMapLayer>
+      <Name>Parcels</Name>
+      <ResourceId>Library://UnitTests/Layers/Parcels.LayerDefinition</ResourceId>
+      <Selectable>true</Selectable>
+      <ShowInLegend>true</ShowInLegend>
+      <LegendLabel>Parcels</LegendLabel>
+      <ExpandInLegend>false</ExpandInLegend>
+    </BaseMapLayer>
+    <BaseMapLayer>
+      <Name>VotingDistricts</Name>
+      <ResourceId>Library://UnitTests/Layers/VotingDistricts.LayerDefinition</ResourceId>
+      <Selectable>true</Selectable>
+      <ShowInLegend>true</ShowInLegend>
+      <LegendLabel>Voting Districts</LegendLabel>
+      <ExpandInLegend>false</ExpandInLegend>
+    </BaseMapLayer>
+  </BaseMapLayerGroup>
+</TileSetDefinition>

Added: sandbox/jng/tiling/UnitTest/TestData/TileService/UT_LinkedTileSet.mdf
===================================================================
--- sandbox/jng/tiling/UnitTest/TestData/TileService/UT_LinkedTileSet.mdf	                        (rev 0)
+++ sandbox/jng/tiling/UnitTest/TestData/TileService/UT_LinkedTileSet.mdf	2014-06-02 22:33:06 UTC (rev 8180)
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MapDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="MapDefinition-3.0.0.xsd" version="3.0.0">
+  <Name>Base Map linked to Tile Set</Name>
+  <CoordinateSystem>PROJCS["WGS84.PseudoMercator",GEOGCS["LL84",DATUM["WGS84",SPHEROID["WGS84",6378137.000,298.25722293]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Popular Visualisation Pseudo Mercator"],PARAMETER["false_easting",0.000],PARAMETER["false_northing",0.000],PARAMETER["central_meridian",0.00000000000000],UNIT["Meter",1.00000000000000]]</CoordinateSystem>
+  <Extents>
+    <MinX>-9773613.7373958</MinX>
+    <MaxX>-9758770.5921973</MaxX>
+    <MinY>5417109.9090669</MinY>
+    <MaxY>5435129.2308673</MaxY>
+  </Extents>
+  <BackgroundColor>FFF7E1D2</BackgroundColor>
+  <MapLayer>
+    <Name>RoadCenterLines</Name>
+    <ResourceId>Library://UnitTests/Layers/RoadCenterLines.LayerDefinition</ResourceId>
+    <Selectable>false</Selectable>
+    <ShowInLegend>true</ShowInLegend>
+    <LegendLabel>Road CenterLines</LegendLabel>
+    <ExpandInLegend>false</ExpandInLegend>
+    <Visible>true</Visible>
+    <Group></Group>
+  </MapLayer>
+  <TileSetSource>
+    <ResourceId>Library://UnitTests/TileSets/Sheboygan.TileSetDefinition</ResourceId>
+  </TileSetSource>
+</MapDefinition>



More information about the mapguide-commits mailing list