[mapguide-commits] r7495 - in sandbox/jng/createruntimemap: Common/MapGuideCommon/MapLayer Common/MapGuideCommon/Services Server/src/Services/Mapping Server/src/UnitTesting Web/src/HttpHandler

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Wed May 15 08:35:36 PDT 2013


Author: jng
Date: 2013-05-15 08:35:36 -0700 (Wed, 15 May 2013)
New Revision: 7495

Modified:
   sandbox/jng/createruntimemap/Common/MapGuideCommon/MapLayer/Selection.cpp
   sandbox/jng/createruntimemap/Common/MapGuideCommon/MapLayer/Selection.h
   sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/MappingDefs.h
   sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/MappingService.h
   sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/ProxyMappingService.cpp
   sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/ProxyMappingService.h
   sandbox/jng/createruntimemap/Server/src/Services/Mapping/MappingOperationFactory.cpp
   sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.cpp
   sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.h
   sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.vcxproj
   sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.vcxproj.filters
   sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingServiceBuild.cpp
   sandbox/jng/createruntimemap/Server/src/UnitTesting/TestMappingService.cpp
   sandbox/jng/createruntimemap/Server/src/UnitTesting/TestMappingService.h
   sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpCreateRuntimeMap.cpp
   sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpCreateRuntimeMap.h
   sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpResourceStrings.cpp
   sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpResourceStrings.h
Log:
This submission offloads the CREATERUNTIMEMAP implementation off from the web tier to the server tier. This introduces 2 new public methods to MgMappingService:

 - MgByteReader* CreateRuntimeMap(MgResourceIdentifier* mapDefinition, CREFSTRING sessionId, INT32 requestedFeatures, INT32 iconsPerScaleRange);
 - MgByteReader* CreateRuntimeMap(MgResourceIdentifier* mapDefinition, CREFSTRING targetMapName, CREFSTRING sessionId, INT32 iconWidth, INT32 iconHeight, INT32 requestedFeatures, INT32 iconsPerScaleRange);

To support our somewhat peculiar use-case (MgMap/MgSelection creation and saving usually happens on the web tier), we've also added a new internal version of MgSelection::Save() that allows direct passing of the session id instead of the default Save() that tries to look for an attached MgUserInformation from our *server* MgResourceService that doesn't exist.

Offloading the logic to the server tier allows us to tap directly into the legend icon rendering/stylization code and avoid TCP/IP ping-pong between the web and server tiers (especially if we're going to be fetching lots of MdfModel::LayerDefinition objects and legend icons). The only server <-> web tier transmissions now as a result, are the API method + parameters to invoke this API in the server tier and the XML response that comes back. The CREATERUNTIMEMAP HTTP operation, is now just a thin proxy service method invoker like all other HTTP operations.

Because this is now a public API addition, the Mapping Service test suite has been updated to exercise this new API.

Modified: sandbox/jng/createruntimemap/Common/MapGuideCommon/MapLayer/Selection.cpp
===================================================================
--- sandbox/jng/createruntimemap/Common/MapGuideCommon/MapLayer/Selection.cpp	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Common/MapGuideCommon/MapLayer/Selection.cpp	2013-05-15 15:35:36 UTC (rev 7495)
@@ -150,7 +150,20 @@
     MgResource::Save(resourceService, resId);
 }
 
+//////////////////////////////////////////////////////////////////
+// Save the resource
+//
+void MgSelection::Save(MgResourceService* resourceService, CREFSTRING sessionId, CREFSTRING mapName)
+{
+    if (sessionId.empty())
+    {
+        throw new MgSessionExpiredException(L"MgSelection.Save",__LINE__,__WFILE__, NULL, L"MgSelectionSaveWithEmptySession", NULL);
+    }
 
+    Ptr<MgResourceIdentifier> resId = new MgResourceIdentifier(GetResourceName(sessionId, mapName));
+    MgResource::Save(resourceService, resId);
+}
+
 //////////////////////////////////////////////////////////////////
 STRING MgSelection::GetResourceName(CREFSTRING sessionId, CREFSTRING mapName)
 {

Modified: sandbox/jng/createruntimemap/Common/MapGuideCommon/MapLayer/Selection.h
===================================================================
--- sandbox/jng/createruntimemap/Common/MapGuideCommon/MapLayer/Selection.h	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Common/MapGuideCommon/MapLayer/Selection.h	2013-05-15 15:35:36 UTC (rev 7495)
@@ -189,6 +189,9 @@
     //
     virtual ~MgSelection();
 
+INTERNAL_API:
+    void Save(MgResourceService* resourceService, CREFSTRING sessionId, CREFSTRING mapName);
+
 protected:
 
     void Dispose();

Modified: sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/MappingDefs.h
===================================================================
--- sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/MappingDefs.h	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/MappingDefs.h	2013-05-15 15:35:36 UTC (rev 7495)
@@ -103,6 +103,8 @@
     static const int GeneratePlot2              = 0x1111EE09;
     static const int GeneratePlot3              = 0x1111EE0A;
     static const int GenerateLegendImage        = 0x1111EE0D;
+    static const int CreateRuntimeMap           = 0x1111EE0E;
+    static const int CreateRuntimeMap2          = 0x1111EE0F;
 };
 /// \endcond
 

Modified: sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/MappingService.h
===================================================================
--- sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/MappingService.h	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/MappingService.h	2013-05-15 15:35:36 UTC (rev 7495)
@@ -315,6 +315,7 @@
         MgMapPlotCollection* mapPlots,
         MgDwfVersion* dwfVersion) = 0;
 
+    ////////////////////////////////////////////////////////////////////////////////
     /// \brief
     /// GenerateLegendImage() returns the legend image for the specified layer.
     ///
@@ -372,6 +373,94 @@
                                               INT32 geomType,
                                               INT32 themeCategory) = 0;
 
+    ////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Creates a new runtime map from the specified Map Definition resource id and returns an XML-based description of the runtime
+    /// map
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param mapDefinition (MgResourceIdentifier)
+    /// MgResourceIdentifier object identifying the map definition resource.
+    /// \param requestedFeatures (int)
+    /// A bitmask representing the desired information to return in the XML response: 
+    /// 1=Layer/Group structure, 2=Layer Icons, 4=Layer Feature Source Information
+    /// \param iconsPerScaleRange (int)
+    /// The number of legend icons per scale range to render inline in the XML response as base64 strings. 
+    /// If a scale range contains a number of rules that exceeds this value, only the first and
+    /// last rules of a type style in the scale range will have inline icons
+    ///
+    /// \remarks
+    /// The bitmask values of 2 (Layer Icons) and 4 (Layer Feature Source Information) have no effect if 1 (Layer/Group structure)
+    /// is not specified
+    ///
+    /// \return
+    /// Returns an XML-based description of the runtime map
+    ///
+    virtual MgByteReader* CreateRuntimeMap(MgResourceIdentifier* mapDefinition,
+                                           CREFSTRING sessionId,
+                                           INT32 requestedFeatures,
+                                           INT32 iconsPerScaleRange) = 0;
+
+    ////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Creates a new runtime map from the specified Map Definition resource id and returns an XML-based description of the runtime
+    /// map
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int iconWidth, int iconHeight, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int iconWidth, int iconHeight, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int iconWidth, int iconHeight, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param mapDefinition (MgResourceIdentifier)
+    /// MgResourceIdentifier object identifying the map definition resource.
+    /// \param targetMapName (String/string)
+    /// The desired name of the runtime map
+    /// \param sessionId (String/string)
+    /// The session ID
+    /// \param iconWidth (int)
+    /// The width of each individual inline legend icons. Has no effect if icons was not requested in the response.
+    /// \param iconHeight (int)
+    /// The height of each individual inline legend icons. Has no effect if icons was not requested in the response.
+    /// \param requestedFeatures (int)
+    /// A bitmask representing the desired information to return in the XML response: 
+    /// 1=Layer/Group structure, 2=Layer Icons, 4=Layer Feature Source Information
+    /// \param iconsPerScaleRange (int)
+    /// The number of legend icons per scale range to render inline in the XML response as base64 strings. 
+    /// If a scale range contains a number of rules that exceeds this value, only the first and
+    /// last rules of a type style in the scale range will have inline icons
+    ///
+    /// \remarks
+    /// The bitmask values of 2 (Layer Icons) and 4 (Layer Feature Source Information) have no effect if 1 (Layer/Group structure)
+    /// is not specified
+    ///
+    /// \return
+    /// Returns an XML-based description of the runtime map
+    ///
+    virtual MgByteReader* CreateRuntimeMap(MgResourceIdentifier* mapDefinition,
+                                           CREFSTRING targetMapName,
+                                           CREFSTRING sessionId,
+                                           INT32 iconWidth,
+                                           INT32 iconHeight,
+                                           INT32 requestedFeatures,
+                                           INT32 iconsPerScaleRange) = 0;
+                                             
+
 EXTERNAL_API:
 
     //////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -543,7 +632,9 @@
         opIdQueryFeaturesWms        =  0x1111EE08,
         opIdGeneratePlot2           =  0x1111EE09,
         opIdGeneratePlot3           =  0x1111EE0A,
-        opIdGenerateLegendImage     =  0x1111EE0D
+        opIdGenerateLegendImage     =  0x1111EE0D,
+        opIdCreateRuntimeMap        =  0x1111EE0E,
+        opIdCreateRuntimeMap2       =  0x1111EE0F
     };
 };
 /// \}

Modified: sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/ProxyMappingService.cpp
===================================================================
--- sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/ProxyMappingService.cpp	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/ProxyMappingService.cpp	2013-05-15 15:35:36 UTC (rev 7495)
@@ -377,6 +377,134 @@
     return (MgByteReader*)cmd.GetReturnValue().val.m_obj;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Creates a new runtime map from the specified Map Definition resource id and returns an XML-based description of the runtime
+/// map
+///
+/// <!-- Syntax in .Net, Java, and PHP -->
+/// \htmlinclude DotNetSyntaxTop.html
+/// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int requestedFeatures, int iconsPerScaleRange);
+/// \htmlinclude SyntaxBottom.html
+/// \htmlinclude JavaSyntaxTop.html
+/// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int requestedFeatures, int iconsPerScaleRange);
+/// \htmlinclude SyntaxBottom.html
+/// \htmlinclude PHPSyntaxTop.html
+/// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int requestedFeatures, int iconsPerScaleRange);
+/// \htmlinclude SyntaxBottom.html
+///
+/// \param mapDefinition (MgResourceIdentifier)
+/// MgResourceIdentifier object identifying the map definition resource.
+/// \param requestedFeatures (int)
+/// A bitmask representing the desired information to return in the XML response: 
+/// 1=Layer/Group structure, 2=Layer Icons, 4=Layer Feature Source Information
+/// \param iconsPerScaleRange (int)
+/// The number of legend icons per scale range to render inline in the XML response as base64 strings. 
+/// If a scale range contains a number of rules that exceeds this value, only the first and
+/// last rules of a type style in the scale range will have inline icons
+///
+/// \remarks
+/// The bitmask values of 2 (Layer Icons) and 4 (Layer Feature Source Information) have no effect if 1 (Layer/Group structure)
+/// is not specified
+///
+/// \return
+/// Returns an XML-based description of the runtime map
+///
+MgByteReader* MgProxyMappingService::CreateRuntimeMap(MgResourceIdentifier* mapDefinition,
+                                                      CREFSTRING sessionId,
+                                                      INT32 requestedFeatures,
+                                                      INT32 iconsPerScaleRange)
+{
+    MgCommand cmd;
+
+    cmd.ExecuteCommand(m_connProp,
+                       MgCommand::knObject,
+                       MgMappingServiceOpId::CreateRuntimeMap,
+                       4,
+                       Mapping_Service,
+                       BUILD_VERSION(2,6,0),
+                       MgCommand::knObject,    mapDefinition,
+                       MgCommand::knString,    sessionId,
+                       MgCommand::knInt32,     requestedFeatures,
+                       MgCommand::knInt32,     iconsPerScaleRange,
+                       MgCommand::knNone);
+
+    SetWarning(cmd.GetWarningObject());
+
+    return (MgByteReader*)cmd.GetReturnValue().val.m_obj;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Creates a new runtime map from the specified Map Definition resource id and returns an XML-based description of the runtime
+/// map
+///
+/// <!-- Syntax in .Net, Java, and PHP -->
+/// \htmlinclude DotNetSyntaxTop.html
+/// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int iconWidth, int iconHeight, int requestedFeatures, int iconsPerScaleRange);
+/// \htmlinclude SyntaxBottom.html
+/// \htmlinclude JavaSyntaxTop.html
+/// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int iconWidth, int iconHeight, int requestedFeatures, int iconsPerScaleRange);
+/// \htmlinclude SyntaxBottom.html
+/// \htmlinclude PHPSyntaxTop.html
+/// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int iconWidth, int iconHeight, int requestedFeatures, int iconsPerScaleRange);
+/// \htmlinclude SyntaxBottom.html
+///
+/// \param mapDefinition (MgResourceIdentifier)
+/// MgResourceIdentifier object identifying the map definition resource.
+/// \param targetMapName (String/string)
+/// The desired name of the runtime map
+/// \param sessionId (String/string)
+/// The session ID
+/// \param iconWidth (int)
+/// The width of each individual inline legend icons. Has no effect if icons was not requested in the response.
+/// \param iconHeight (int)
+/// The height of each individual inline legend icons. Has no effect if icons was not requested in the response.
+/// \param requestedFeatures (int)
+/// A bitmask representing the desired information to return in the XML response: 
+/// 1=Layer/Group structure, 2=Layer Icons, 4=Layer Feature Source Information
+/// \param iconsPerScaleRange (int)
+/// The number of legend icons per scale range to render inline in the XML response as base64 strings. 
+/// If a scale range contains a number of rules that exceeds this value, only the first and
+/// last rules of a type style in the scale range will have inline icons
+///
+/// \remarks
+/// The bitmask values of 2 (Layer Icons) and 4 (Layer Feature Source Information) have no effect if 1 (Layer/Group structure)
+/// is not specified
+///
+/// \return
+/// Returns an XML-based description of the runtime map
+///
+MgByteReader* MgProxyMappingService::CreateRuntimeMap(MgResourceIdentifier* mapDefinition,
+                                                      CREFSTRING targetMapName,
+                                                      CREFSTRING sessionId,
+                                                      INT32 iconWidth,
+                                                      INT32 iconHeight,
+                                                      INT32 requestedFeatures,
+                                                      INT32 iconsPerScaleRange)
+{
+    MgCommand cmd;
+
+    cmd.ExecuteCommand(m_connProp,
+                       MgCommand::knObject,
+                       MgMappingServiceOpId::CreateRuntimeMap2,
+                       7,
+                       Mapping_Service,
+                       BUILD_VERSION(2,6,0),
+                       MgCommand::knObject,    mapDefinition,
+                       MgCommand::knString,    targetMapName,
+                       MgCommand::knString,    sessionId,
+                       MgCommand::knInt32,     iconWidth,
+                       MgCommand::knInt32,     iconHeight,
+                       MgCommand::knInt32,     requestedFeatures,
+                       MgCommand::knInt32,     iconsPerScaleRange,
+                       MgCommand::knNone);
+
+    SetWarning(cmd.GetWarningObject());
+
+    return (MgByteReader*)cmd.GetReturnValue().val.m_obj;
+}
+
 //////////////////////////////////////////////////////////////////
 /// \brief
 /// Sets the connection properties for the Proxy Service.  This

Modified: sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/ProxyMappingService.h
===================================================================
--- sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/ProxyMappingService.h	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Common/MapGuideCommon/Services/ProxyMappingService.h	2013-05-15 15:35:36 UTC (rev 7495)
@@ -336,6 +336,93 @@
                                               INT32 geomType,
                                               INT32 themeCategory);
 
+    ////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Creates a new runtime map from the specified Map Definition resource id and returns an XML-based description of the runtime
+    /// map
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param mapDefinition (MgResourceIdentifier)
+    /// MgResourceIdentifier object identifying the map definition resource.
+    /// \param requestedFeatures (int)
+    /// A bitmask representing the desired information to return in the XML response: 
+    /// 1=Layer/Group structure, 2=Layer Icons, 4=Layer Feature Source Information
+    /// \param iconsPerScaleRange (int)
+    /// The number of legend icons per scale range to render inline in the XML response as base64 strings. 
+    /// If a scale range contains a number of rules that exceeds this value, only the first and
+    /// last rules of a type style in the scale range will have inline icons
+    ///
+    /// \remarks
+    /// The bitmask values of 2 (Layer Icons) and 4 (Layer Feature Source Information) have no effect if 1 (Layer/Group structure)
+    /// is not specified
+    ///
+    /// \return
+    /// Returns an XML-based description of the runtime map
+    ///
+    virtual MgByteReader* CreateRuntimeMap(MgResourceIdentifier* mapDefinition,
+                                           CREFSTRING sessionId,
+                                           INT32 requestedFeatures,
+                                           INT32 iconsPerScaleRange);
+
+    ////////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Creates a new runtime map from the specified Map Definition resource id and returns an XML-based description of the runtime
+    /// map
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int iconWidth, int iconHeight, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int iconWidth, int iconHeight, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual MgByteReader CreateRuntimeMap(MgResourceIdentifier mapDefinition, int iconWidth, int iconHeight, int requestedFeatures, int iconsPerScaleRange);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param mapDefinition (MgResourceIdentifier)
+    /// MgResourceIdentifier object identifying the map definition resource.
+    /// \param targetMapName (String/string)
+    /// The desired name of the runtime map
+    /// \param sessionId (String/string)
+    /// The session ID
+    /// \param iconWidth (int)
+    /// The width of each individual inline legend icons. Has no effect if icons was not requested in the response.
+    /// \param iconHeight (int)
+    /// The height of each individual inline legend icons. Has no effect if icons was not requested in the response.
+    /// \param requestedFeatures (int)
+    /// A bitmask representing the desired information to return in the XML response: 
+    /// 1=Layer/Group structure, 2=Layer Icons, 4=Layer Feature Source Information
+    /// \param iconsPerScaleRange (int)
+    /// The number of legend icons per scale range to render inline in the XML response as base64 strings. 
+    /// If a scale range contains a number of rules that exceeds this value, only the first and
+    /// last rules of a type style in the scale range will have inline icons
+    ///
+    /// \remarks
+    /// The bitmask values of 2 (Layer Icons) and 4 (Layer Feature Source Information) have no effect if 1 (Layer/Group structure)
+    /// is not specified
+    ///
+    /// \return
+    /// Returns an XML-based description of the runtime map
+    ///
+    virtual MgByteReader* CreateRuntimeMap(MgResourceIdentifier* mapDefinition,
+                                           CREFSTRING targetMapName,
+                                           CREFSTRING sessionId,
+                                           INT32 iconWidth,
+                                           INT32 iconHeight,
+                                           INT32 requestedFeatures,
+                                           INT32 iconsPerScaleRange);
+
 INTERNAL_API:
     //////////////////////////////////////////////////////////////////
     /// \brief

Modified: sandbox/jng/createruntimemap/Server/src/Services/Mapping/MappingOperationFactory.cpp
===================================================================
--- sandbox/jng/createruntimemap/Server/src/Services/Mapping/MappingOperationFactory.cpp	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Server/src/Services/Mapping/MappingOperationFactory.cpp	2013-05-15 15:35:36 UTC (rev 7495)
@@ -18,6 +18,7 @@
 #include "ServerMappingServiceDefs.h"
 #include "MappingOperationFactory.h"
 
+#include "OpCreateRuntimeMap.h"
 #include "OpGenerateMap.h"
 #include "OpGenerateMapUpdate.h"
 #include "OpGeneratePlot.h"
@@ -195,6 +196,30 @@
         }
         break;
 
+    case MgMappingService::opIdCreateRuntimeMap:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(2,6):
+            handler.reset(new MgOpCreateRuntimeMap());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgDrawingOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
+
+    case MgMappingService::opIdCreateRuntimeMap2:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(2,6):
+            handler.reset(new MgOpCreateRuntimeMap());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgDrawingOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
+
     default:
         throw new MgInvalidOperationException(
             L"MgMappingOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);

Modified: sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.cpp
===================================================================
--- sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.cpp	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.cpp	2013-05-15 15:35:36 UTC (rev 7495)
@@ -43,7 +43,12 @@
 
 #define LEGEND_BITMAP_SIZE 16
 
+#define REQUEST_LAYER_STRUCTURE         1 /* Request layer and group structure */
+#define REQUEST_LAYER_ICONS             2 /* Request layer scale and icon information */
+#define REQUEST_LAYER_FEATURE_SOURCE    4 /* Request information about a layer's feature source */
 
+typedef std::map<STRING, MdfModel::LayerDefinition*> LayerDefinitionMap;
+
 //for use by observation mesh transformation
 const STRING SRS_LL84 = L"GEOGCS[\"LL84\",DATUM[\"WGS84\",SPHEROID[\"WGS84\",6378137,298.25722293287],TOWGS84[0,0,0,0,0,0,0]],PRIMEM[\"Greenwich\",0],UNIT[\"Degrees\",0.01745329252]]";
 
@@ -1856,3 +1861,435 @@
 {
     // Do nothing.  No connection properties are required for Server-side service objects.
 }
+
+MgByteReader* MgServerMappingService::CreateRuntimeMap(MgResourceIdentifier* mapDefinition,
+                                                       CREFSTRING sessionId,
+                                                       INT32 requestedFeatures,
+                                                       INT32 iconsPerScaleRange)
+{
+    CHECKNULL(mapDefinition, L"MgServerMappingService.CreateRuntimeMap");
+    STRING mapName = mapDefinition->GetName();
+    return CreateRuntimeMap(mapDefinition, mapName, sessionId, LEGEND_BITMAP_SIZE, LEGEND_BITMAP_SIZE, requestedFeatures, iconsPerScaleRange);
+}
+
+MgByteReader* MgServerMappingService::CreateRuntimeMap(MgResourceIdentifier* mapDefinition,
+                                                       CREFSTRING targetMapName,
+                                                       CREFSTRING sessionId,
+                                                       INT32 iconWidth,
+                                                       INT32 iconHeight,
+                                                       INT32 requestedFeatures,
+                                                       INT32 iconsPerScaleRange)
+{
+    CHECKNULL(mapDefinition, L"MgServerMappingService.CreateRuntimeMap");
+    Ptr<MgByteReader> byteReader;
+    LayerDefinitionMap layerDefinitionMap;
+
+    MG_SERVER_MAPPING_SERVICE_TRY()
+
+    if (m_svcResource == NULL)
+        InitializeResourceService();
+
+    Ptr<MgSiteConnection> siteConn = new MgSiteConnection();
+    Ptr<MgUserInformation> userInfo = new MgUserInformation(sessionId);
+    siteConn->Open(userInfo);
+    Ptr<MgMap> map = new MgMap(siteConn);
+    map->Create(mapDefinition, targetMapName);
+    
+    STRING sStateId = L"Session:";
+    sStateId += sessionId;
+    sStateId += L"//";
+    sStateId += targetMapName;
+    sStateId += L".";
+    sStateId += MgResourceType::Map;
+
+    Ptr<MgResourceIdentifier> mapStateId = new MgResourceIdentifier(sStateId);
+    Ptr<MgSelection> sel = new MgSelection(map);
+    //Call our special Save() API that doesn't try to look for a MgUserInformation that's not
+    //there
+    sel->Save(m_svcResource, sessionId, targetMapName);
+    map->Save(m_svcResource, mapStateId);
+
+    //TODO: Possible future caching opportunity?
+    std::string xml;
+    xml.append("<RuntimeMap>\n");
+    // ------------------------------ Site Version ----------------------------------//
+    xml.append("<SiteVersion>");
+    MgServerManager* serverMgr = MgServerManager::GetInstance();
+    xml.append(MgUtil::WideCharToMultiByte(serverMgr->GetSiteVersion()));
+    xml.append("</SiteVersion>\n");
+    // ------------------------------ Session ID --------------------------------- //
+    xml.append("<SessionId>");
+    xml.append(MgUtil::WideCharToMultiByte(sessionId));
+    xml.append("</SessionId>\n");
+    // ------------------------------ Map Name --------------------------------- //
+    xml.append("<Name>");
+    xml.append(MgUtil::WideCharToMultiByte(targetMapName));
+    xml.append("</Name>\n");
+    // ------------------------------ Map Definition ID --------------------------------- //
+    xml.append("<MapDefinition>");
+    xml.append(MgUtil::WideCharToMultiByte(mapDefinition->ToString()));
+    xml.append("</MapDefinition>\n");
+    // ------------------------------ Background Color ---------------------------------- //
+    xml.append("<BackgroundColor>");
+    xml.append(MgUtil::WideCharToMultiByte(map->GetBackgroundColor()));
+    xml.append("</BackgroundColor>");
+    // ------------------------------ Coordinate System --------------------------------- //
+    xml.append("<CoordinateSystem>\n");
+    xml.append("<Wkt>");
+    STRING srs = map->GetMapSRS();
+    xml.append(MgUtil::WideCharToMultiByte(MgUtil::ReplaceEscapeCharInXml(srs)));
+    xml.append("</Wkt>\n");
+    Ptr<MgCoordinateSystemFactory> fact = new MgCoordinateSystemFactory();
+    std::string sEpsg;
+    std::string sMentor;
+    std::string sMpu;
+    try
+    {
+        Ptr<MgCoordinateSystem> cs = fact->Create(srs);
+        if (!srs.empty())
+            MgUtil::DoubleToString(cs->ConvertCoordinateSystemUnitsToMeters(1.0), sMpu);
+        else
+            sMpu = "1.0";
+        sMentor = MgUtil::WideCharToMultiByte(cs->GetCsCode());
+        INT32 epsg = cs->GetEpsgCode();
+        MgUtil::Int32ToString(epsg, sEpsg);
+    }
+    catch (MgException* ex)
+    {
+        SAFE_RELEASE(ex);
+    }
+    xml.append("<MentorCode>");
+    xml.append(sMentor);
+    xml.append("</MentorCode>\n");
+    xml.append("<EpsgCode>");
+    xml.append(sEpsg);
+    xml.append("</EpsgCode>\n");
+    xml.append("<MetersPerUnit>");
+    xml.append(sMpu);
+    xml.append("</MetersPerUnit>\n");
+    xml.append("</CoordinateSystem>");
+    // ------------------------------ Extents --------------------------------- //
+    std::string sExtents;
+    Ptr<MgEnvelope> extents = map->GetMapExtent();
+    extents->ToXml(sExtents);
+    xml.append("<Extents>\n");
+    xml.append(sExtents);
+    xml.append("</Extents>");
+    // ---------------------- Optional things if requested -------------------- //
+    if ((requestedFeatures & REQUEST_LAYER_STRUCTURE) == REQUEST_LAYER_STRUCTURE)
+    {
+        //Build our LayerDefinition map for code below that requires it
+        if ((requestedFeatures & REQUEST_LAYER_ICONS) == REQUEST_LAYER_ICONS)
+        {
+            Ptr<MgStringCollection> layerIds = new MgStringCollection();
+            Ptr<MgLayerCollection> layers = map->GetLayers();
+            for (INT32 i = 0; i < layers->GetCount(); i++)
+            {
+                Ptr<MgLayerBase> layer = layers->GetItem(i);
+                Ptr<MgResourceIdentifier> ldfId = layer->GetLayerDefinition();
+                layerIds->Add(ldfId->ToString());
+            }
+
+            Ptr<MgStringCollection> layerContents = m_svcResource->GetResourceContents(layerIds, NULL);
+            for (INT32 i = 0; i < layerIds->GetCount(); i++)
+            {
+                STRING ldfId = layerIds->GetItem(i);
+                STRING content = layerContents->GetItem(i);
+                MdfModel::LayerDefinition* ldf = MgLayerBase::GetLayerDefinition(content);
+                layerDefinitionMap[ldfId] = ldf;
+            }
+        }
+
+        // ----------- Some pre-processing before we do groups/layers ------------- //
+        Ptr<MgLayerGroupCollection> groups = map->GetLayerGroups();
+        Ptr<MgLayerCollection> layers = map->GetLayers();
+        for (INT32 i = 0; i < groups->GetCount(); i++)
+        {
+            Ptr<MgLayerGroup> group = groups->GetItem(i);
+            Ptr<MgLayerGroup> parent = group->GetGroup();
+            CreateGroupItem(group, parent, xml);
+        }
+        for (INT32 i = 0; i < layers->GetCount(); i++)
+        {
+            Ptr<MgLayerBase> layer = layers->GetItem(i);
+            Ptr<MgLayerGroup> parent = layer->GetGroup();
+            
+            MdfModel::LayerDefinition* layerDef = NULL;
+            Ptr<MgResourceIdentifier> layerid = layer->GetLayerDefinition();
+            LayerDefinitionMap::iterator it = layerDefinitionMap.find(layerid->ToString());
+            if (it != layerDefinitionMap.end())
+                layerDef = it->second;
+
+            CreateLayerItem(requestedFeatures, iconsPerScaleRange, iconWidth, iconHeight, layer, parent, layerDef, xml);
+        }
+    }
+    // ------------------------ Finite Display Scales (if any) ------------------------- //
+    INT32 fsCount = map->GetFiniteDisplayScaleCount();
+    if (fsCount > 0)
+    {
+        for (INT32 i = 0; i < fsCount; i++)
+        {
+            xml.append("<FiniteDisplayScale>");
+            double dScale = map->GetFiniteDisplayScaleAt(i);
+            std::string sScale;
+            MgUtil::DoubleToString(dScale, sScale);
+            xml.append(sScale);
+            xml.append("</FiniteDisplayScale>\n");
+        }
+    }
+    xml.append("</RuntimeMap>");
+
+    Ptr<MgByteSource> byteSource = new MgByteSource((BYTE_ARRAY_IN)xml.c_str(), (INT32)xml.length());
+    byteSource->SetMimeType(MgMimeType::Xml);
+    byteReader = byteSource->GetReader();
+
+    MG_SERVER_MAPPING_SERVICE_CATCH(L"MgServerMappingService.CreateRuntimeMap")
+
+    //Cleanup our LayerDefinition pointers. Do it here so we don't leak on any exception
+    for (LayerDefinitionMap::iterator it = layerDefinitionMap.begin(); it != layerDefinitionMap.end(); it++)
+    {
+        MdfModel::LayerDefinition* ldf = it->second;
+        delete ldf;
+    }
+    layerDefinitionMap.clear();
+
+    MG_SERVER_MAPPING_SERVICE_THROW()
+
+    return byteReader.Detach();
+}
+
+void MgServerMappingService::CreateGroupItem(MgLayerGroup* group, MgLayerGroup* parent, std::string& xml)
+{
+    MG_SERVER_MAPPING_SERVICE_TRY()
+
+    STRING groupName = group->GetName();
+    xml.append("<Group>\n");
+    xml.append("<Name>");
+    xml.append(MgUtil::WideCharToMultiByte(groupName));
+    xml.append("</Name>\n");
+    xml.append("<Type>");
+    INT32 gType = group->GetLayerGroupType();
+    std::string sType;
+    MgUtil::Int32ToString(gType, sType);
+    xml.append(sType);
+    xml.append("</Type>\n");
+    xml.append("<LegendLabel>");
+    xml.append(MgUtil::WideCharToMultiByte(MgUtil::ReplaceEscapeCharInXml(group->GetLegendLabel())));
+    xml.append("</LegendLabel>\n");
+    xml.append("<ObjectId>");
+    xml.append(MgUtil::WideCharToMultiByte(group->GetObjectId()));
+    xml.append("</ObjectId>\n");
+    if (NULL != parent)
+    {
+        xml.append("<ParentId>");
+        xml.append(MgUtil::WideCharToMultiByte(parent->GetObjectId()));
+        xml.append("</ParentId>\n");
+    }
+    xml.append("<DisplayInLegend>");
+    xml.append(group->GetDisplayInLegend() ? "true" : "false");
+    xml.append("</DisplayInLegend>\n");
+    xml.append("<ExpandInLegend>");
+    xml.append(group->GetExpandInLegend() ? "true" : "false");
+    xml.append("</ExpandInLegend>\n");
+    xml.append("<Visible>");
+    xml.append(group->GetVisible() ? "true" : "false");
+    xml.append("</Visible>\n");
+    xml.append("<ActuallyVisible>");
+    xml.append(group->IsVisible() ? "true" : "false");
+    xml.append("</ActuallyVisible>\n");
+    xml.append("</Group>");
+
+    MG_SERVER_MAPPING_SERVICE_CATCH_AND_THROW(L"MgServerMappingService.CreateGroupItem")
+}
+
+void MgServerMappingService::CreateLayerItem(INT32 requestedFeatures, INT32 iconsPerScaleRange, INT32 iconWidth, INT32 iconHeight, MgLayerBase* layer, MgLayerGroup* parent, MdfModel::LayerDefinition* ldf, std::string& xml)
+{
+    MG_SERVER_MAPPING_SERVICE_TRY()
+
+    xml.append("<Layer>\n");
+    xml.append("<Type>");
+    std::string sLayerType;
+    MgUtil::Int32ToString(layer->GetLayerType(), sLayerType);
+    xml.append(sLayerType);
+    xml.append("</Type>\n");
+    xml.append("<LayerDefinition>");
+    Ptr<MgResourceIdentifier> layerDefId = layer->GetLayerDefinition();
+    STRING ldfId = layerDefId->ToString();
+    xml.append(MgUtil::WideCharToMultiByte(ldfId));
+    xml.append("</LayerDefinition>\n");
+    xml.append("<Name>");
+    xml.append(MgUtil::WideCharToMultiByte(layer->GetName()));
+    xml.append("</Name>\n");
+    xml.append("<LegendLabel>");
+    xml.append(MgUtil::WideCharToMultiByte(MgUtil::ReplaceEscapeCharInXml(layer->GetLegendLabel())));
+    xml.append("</LegendLabel>\n");
+    xml.append("<ObjectId>");
+    xml.append(MgUtil::WideCharToMultiByte(layer->GetObjectId()));
+    xml.append("</ObjectId>\n");
+    if (NULL != parent)
+    {
+        xml.append("<ParentId>");
+        xml.append(MgUtil::WideCharToMultiByte(parent->GetObjectId()));
+        xml.append("</ParentId>\n");
+    }
+    xml.append("<Selectable>");
+    xml.append(layer->GetSelectable() ? "true" : "false");
+    xml.append("</Selectable>\n");
+    xml.append("<DisplayInLegend>");
+    xml.append(layer->GetDisplayInLegend() ? "true" : "false");
+    xml.append("</DisplayInLegend>\n");
+    xml.append("<ExpandInLegend>");
+    xml.append(layer->GetExpandInLegend() ? "true" : "false");
+    xml.append("</ExpandInLegend>\n");
+    xml.append("<Visible>");
+    xml.append(layer->GetVisible() ? "true" : "false");
+    xml.append("</Visible>\n");
+    xml.append("<ActuallyVisible>");
+    xml.append(layer->IsVisible() ? "true" : "false");
+    xml.append("</ActuallyVisible>\n");
+    // ----------------------- Optional things if requested ------------------------- //
+    if ((requestedFeatures & REQUEST_LAYER_FEATURE_SOURCE) == REQUEST_LAYER_FEATURE_SOURCE)
+    {
+        xml.append("<FeatureSource>\n");
+        xml.append("<ResourceId>");
+        xml.append(MgUtil::WideCharToMultiByte(layer->GetFeatureSourceId()));
+        xml.append("</ResourceId>\n");
+        xml.append("<ClassName>");
+        xml.append(MgUtil::WideCharToMultiByte(layer->GetFeatureClassName()));
+        xml.append("</ClassName>\n");
+        xml.append("<Geometry>");
+        xml.append(MgUtil::WideCharToMultiByte(layer->GetFeatureGeometryName()));
+        xml.append("</Geometry>\n");
+        xml.append("</FeatureSource>\n");
+    }
+    
+    if (NULL != ldf)
+    {
+        MdfModel::VectorLayerDefinition* vl = dynamic_cast<MdfModel::VectorLayerDefinition*>(ldf);
+        if (NULL != vl)
+        {
+            MdfModel::VectorScaleRangeCollection* vsrs = vl->GetScaleRanges();
+            for (INT32 i = 0; i < vsrs->GetCount(); i++)
+            {
+                MdfModel::VectorScaleRange* vsr = vsrs->GetAt(i);
+                xml.append("<ScaleRange>\n");
+                xml.append("<MinScale>");
+                std::string sMinScale;
+                MgUtil::DoubleToString(vsr->GetMinScale(), sMinScale);
+                xml.append(sMinScale);
+                xml.append("</MinScale>\n");
+                xml.append("<MaxScale>");
+                std::string sMaxScale;
+                MgUtil::DoubleToString(vsr->GetMaxScale(), sMaxScale);
+                xml.append(sMaxScale);
+                xml.append("</MaxScale>\n");
+
+                double dScale = (vsr->GetMaxScale() + vsr->GetMinScale()) / 2.0;
+                MdfModel::FeatureTypeStyleCollection* ftsc = vsr->GetFeatureTypeStyles();
+
+                INT32 nIconCount = 0;
+                for (INT32 j = 0; j < ftsc->GetCount(); j++)
+                {
+                    MdfModel::FeatureTypeStyle* fts = ftsc->GetAt(j);
+                    if (fts->IsShowInLegend())
+                    {
+                        MdfModel::RuleCollection* rules = fts->GetRules();
+                        nIconCount += rules->GetCount();
+                    }
+                }
+
+                //This theme will be compressed if we're over the specified limit for this scale range
+                bool bCompress = (nIconCount > iconsPerScaleRange);
+
+                for (INT32 j = 0; j < ftsc->GetCount(); j++)
+                {
+                    MdfModel::FeatureTypeStyle* fts = ftsc->GetAt(j);
+                    if (!fts->IsShowInLegend())
+                        continue;
+
+                    MdfModel::PointTypeStyle*       pts = dynamic_cast<MdfModel::PointTypeStyle*>(fts);
+                    MdfModel::LineTypeStyle*        lts = dynamic_cast<MdfModel::LineTypeStyle*>(fts);
+                    MdfModel::AreaTypeStyle*        ats = dynamic_cast<MdfModel::AreaTypeStyle*>(fts);
+                    MdfModel::CompositeTypeStyle*   cts = dynamic_cast<MdfModel::CompositeTypeStyle*>(fts);
+                        
+                    INT32 geomType = 0;
+                    if (pts)
+                        geomType = 1;
+                    else if (lts)
+                        geomType = 2;
+                    else if (ats)
+                        geomType = 3;
+                    else if (cts)
+                        geomType = 4;
+                    INT32 catIndex = 0;
+
+                    MdfModel::RuleCollection* rules = fts->GetRules();
+                    for (INT32 r = 0; r < rules->GetCount(); r++)
+                    {
+                        MdfModel::Rule* rule = rules->GetAt(r);
+                        bool bRequestIcon = false;
+                        if (!bCompress)
+                        {
+                            bRequestIcon = true;
+                        }
+                        else //This is a compressed theme
+                        {
+                            bRequestIcon = (r == 0 || r == rules->GetCount() - 1); //Only first and last rule
+                        }
+
+                        xml.append("<Rule>\n");
+                        //GeometryType and ThemeCategory are required so that deferred icon requests can be made
+                        //back to the GetLegendImage(), especially if we exceed the icons-per-scale-range limit
+                        xml.append("<GeometryType>");
+                        std::string sGeomType;
+                        MgUtil::Int32ToString(geomType, sGeomType);
+                        xml.append(sGeomType);
+                        xml.append("</GeometryType>\n");
+                        xml.append("<ThemeCategory>");
+                        std::string sThemeCat;
+                        MgUtil::Int32ToString(catIndex, sThemeCat);
+                        xml.append(sThemeCat);
+                        xml.append("</ThemeCategory>\n");
+                        xml.append("<LegendLabel>");
+                        xml.append(MgUtil::WideCharToMultiByte(MgUtil::ReplaceEscapeCharInXml(rule->GetLegendLabel())));
+                        xml.append("</LegendLabel>\n");
+                        xml.append("<Filter>");
+                        xml.append(MgUtil::WideCharToMultiByte(MgUtil::ReplaceEscapeCharInXml(rule->GetFilter())));
+                        xml.append("</Filter>\n");
+                        if (bRequestIcon)
+                        {
+                            xml.append("<Icon>");
+                            Ptr<MgByteReader> iconReader = MgMappingUtil::DrawFTS(m_svcResource, fts, iconWidth, iconHeight, catIndex);
+                            xml.append("<MimeType>");
+                            xml.append(MgUtil::WideCharToMultiByte(iconReader->GetMimeType()));
+                            xml.append("</MimeType>\n");
+                            xml.append("<Content>");
+                            Ptr<MgByteSink> sink = new MgByteSink(iconReader);
+                            Ptr<MgByte> bytes = sink->ToBuffer();
+                            Ptr<MgMemoryStreamHelper> streamHelper = new MgMemoryStreamHelper((INT8*) bytes->Bytes(), bytes->GetLength(), false);
+                            std::string b64 = streamHelper->ToBase64();
+                            xml.append(b64);
+                            xml.append("</Content>\n");
+                            xml.append("</Icon>");
+                        }
+                        xml.append("</Rule>\n");
+
+                        catIndex++;
+                    }
+                }
+
+                xml.append("</ScaleRange>\n");
+            }
+        }
+        else
+        {
+            xml.append("<ScaleRange/>");
+        }
+    }
+    else
+        xml.append("<ScaleRange/>");
+
+    xml.append("</Layer>");
+
+    MG_SERVER_MAPPING_SERVICE_CATCH_AND_THROW(L"MgServerMappingService.CreateLayerItem")
+}
\ No newline at end of file

Modified: sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.h
===================================================================
--- sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.h	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.h	2013-05-15 15:35:36 UTC (rev 7495)
@@ -116,11 +116,26 @@
             INT32 geomType,
             INT32 themeCategory);
 
+        virtual MgByteReader* CreateRuntimeMap(MgResourceIdentifier* mapDefinition,
+                                               CREFSTRING sessionId,
+                                               INT32 requestedFeatures,
+                                               INT32 iconsPerScaleRange);
+
+        virtual MgByteReader* CreateRuntimeMap(MgResourceIdentifier* mapDefinition,
+                                               CREFSTRING targetMapName,
+                                               CREFSTRING sessionId,
+                                               INT32 iconWidth,
+                                               INT32 iconHeight,
+                                               INT32 requestedFeatures,
+                                               INT32 iconsPerScaleRange);
+
         void SetConnectionProperties(MgConnectionProperties* connProp);
 
 // Data Members
 
     private:
+        void CreateGroupItem(MgLayerGroup* group, MgLayerGroup* parent, std::string& xml);
+        void CreateLayerItem(INT32 requestedFeatures, INT32 iconsPerScaleRange, INT32 iconWidth, INT32 iconHeight, MgLayerBase* layer, MgLayerGroup* parent, MdfModel::LayerDefinition* ldf, std::string& xml);
         bool FeatureTypeStyleSupportsGeomType(MdfModel::FeatureTypeStyle* fts, INT32 geomType);
         void MakeUIGraphicsForScaleRange(std::list<RS_UIGraphic>& uiGraphics, std::vector<MgByte*>& uiGraphicSources, MdfModel::VectorScaleRange* sr);
 

Modified: sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.vcxproj
===================================================================
--- sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.vcxproj	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.vcxproj	2013-05-15 15:35:36 UTC (rev 7495)
@@ -208,6 +208,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="OpCreateRuntimeMap.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="OpGenerateLegendImage.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -315,6 +321,7 @@
   <ItemGroup>
     <ClInclude Include="MappingOperation.h" />
     <ClInclude Include="MappingOperationFactory.h" />
+    <ClInclude Include="OpCreateRuntimeMap.h" />
     <ClInclude Include="OpGenerateLegendImage.h" />
     <ClInclude Include="OpGenerateLegendPlot.h" />
     <ClInclude Include="OpGenerateMap.h" />

Modified: sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.vcxproj.filters
===================================================================
--- sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.vcxproj.filters	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingService.vcxproj.filters	2013-05-15 15:35:36 UTC (rev 7495)
@@ -46,6 +46,9 @@
     <ClCompile Include="SEMgSymbolManager.cpp" />
     <ClCompile Include="ServerMappingService.cpp" />
     <ClCompile Include="ServerMappingServiceBuild.cpp" />
+    <ClCompile Include="OpCreateRuntimeMap.cpp">
+      <Filter>Ops</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="MappingOperation.h">
@@ -90,6 +93,9 @@
     <ClInclude Include="ServerMappingDllExport.h" />
     <ClInclude Include="ServerMappingService.h" />
     <ClInclude Include="ServerMappingServiceDefs.h" />
+    <ClInclude Include="OpCreateRuntimeMap.h">
+      <Filter>Ops</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ServerMappingService.rc" />

Modified: sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingServiceBuild.cpp
===================================================================
--- sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingServiceBuild.cpp	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Server/src/Services/Mapping/ServerMappingServiceBuild.cpp	2013-05-15 15:35:36 UTC (rev 7495)
@@ -21,6 +21,7 @@
 #include "MappingOperation.cpp"
 #include "MappingOperationFactory.cpp"
 #include "MappingServiceHandler.cpp"
+#include "OpCreateRuntimeMap.cpp"
 #include "OpGeneratePlot.cpp"
 #include "OpGenerateMap.cpp"
 #include "OpGenerateMapUpdate.cpp"

Modified: sandbox/jng/createruntimemap/Server/src/UnitTesting/TestMappingService.cpp
===================================================================
--- sandbox/jng/createruntimemap/Server/src/UnitTesting/TestMappingService.cpp	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Server/src/UnitTesting/TestMappingService.cpp	2013-05-15 15:35:36 UTC (rev 7495)
@@ -55,9 +55,9 @@
     // This must be done before calling CreateSession()
     MgUserInformation::SetCurrentUserInfo(userInfo);
 
-    STRING session = svcSite->CreateSession();
-    assert(!session.empty());
-    userInfo->SetMgSessionId(session);
+    m_session = svcSite->CreateSession();
+    assert(!m_session.empty());
+    userInfo->SetMgSessionId(m_session);
 
     // Set the current MgUserInformation
     MgUserInformation::SetCurrentUserInfo(userInfo);
@@ -251,7 +251,50 @@
     ACE_DEBUG((LM_INFO, ACE_TEXT("\nMapping Service tests completed.\n\n")));
 }
 
+void TestMappingService::TestCase_CreateRuntimeMap()
+{
+    try
+    {
+        //make a runtime map
+        Ptr<MgResourceIdentifier> mdfres = new MgResourceIdentifier(L"Library://UnitTests/Maps/Sheboygan.MapDefinition");
+        //call the API
+        Ptr<MgByteReader> rtMap = m_svcMapping->CreateRuntimeMap(mdfres, L"UnitTestSheboygan1", m_session, 16, 16, 0, 25);
+        Ptr<MgByteSink> sink = new MgByteSink(rtMap);
+        sink->ToFile(L"../UnitTestFiles/RuntimeMapBarebones.xml");
 
+        rtMap = m_svcMapping->CreateRuntimeMap(mdfres, L"UnitTestSheboygan2", m_session, 16, 16, 1, 25);
+        sink = new MgByteSink(rtMap);
+        sink->ToFile(L"../UnitTestFiles/RuntimeMapLayersAndGroups.xml");
+
+        rtMap = m_svcMapping->CreateRuntimeMap(mdfres, L"UnitTestSheboygan3", m_session, 16, 16, (1 | 2), 25);
+        sink = new MgByteSink(rtMap);
+        sink->ToFile(L"../UnitTestFiles/RuntimeMapLayersAndGroupsWithIcons16x16.xml");
+
+        rtMap = m_svcMapping->CreateRuntimeMap(mdfres, L"UnitTestSheboygan4", m_session, 16, 16, (1 | 2 | 4), 25);
+        sink = new MgByteSink(rtMap);
+        sink->ToFile(L"../UnitTestFiles/RuntimeMapLayersAndGroupsWithIconsAndFeatureSource16x16.xml");
+
+        rtMap = m_svcMapping->CreateRuntimeMap(mdfres, L"UnitTestSheboygan5", m_session, 32, 32, (1 | 2), 25);
+        sink = new MgByteSink(rtMap);
+        sink->ToFile(L"../UnitTestFiles/RuntimeMapLayersAndGroupsWithIcons32x32.xml");
+
+        rtMap = m_svcMapping->CreateRuntimeMap(mdfres, L"UnitTestSheboygan6", m_session, 32, 32, (1 | 2 | 4), 25);
+        sink = new MgByteSink(rtMap);
+        sink->ToFile(L"../UnitTestFiles/RuntimeMapLayersAndGroupsWithIconsAndFeatureSource32x32.xml");
+    }
+    catch(MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch(...)
+    {
+        throw;
+    }
+}
+
+
 void TestMappingService::TestCase_GetMap()
 {
     try

Modified: sandbox/jng/createruntimemap/Server/src/UnitTesting/TestMappingService.h
===================================================================
--- sandbox/jng/createruntimemap/Server/src/UnitTesting/TestMappingService.h	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Server/src/UnitTesting/TestMappingService.h	2013-05-15 15:35:36 UTC (rev 7495)
@@ -34,6 +34,7 @@
     CPPUNIT_TEST(TestCase_GetPlotUsingExtents);
     CPPUNIT_TEST(TestCase_GetPlotUsingExtentsAndExpandToFit);
     CPPUNIT_TEST(TestCase_GetLegendPlot);
+    CPPUNIT_TEST(TestCase_CreateRuntimeMap);
     //CPPUNIT_TEST(TestCase_QueryFeaturesImageMap);
 
     CPPUNIT_TEST(TestEnd); // This must be the very last unit test
@@ -49,6 +50,7 @@
     void TestStart();
     void TestEnd();
 
+    void TestCase_CreateRuntimeMap();
     void TestCase_GetMap();
     void TestCase_GetMapUpdate();
     void TestCase_SaveMap();
@@ -68,6 +70,8 @@
     Ptr<MgSiteConnection> m_siteConnection;
     Ptr<MgResourceService> m_svcResource;
     Ptr<MgMappingService> m_svcMapping;
+
+    STRING m_session;
 };
 
 #endif // TESTMAPPINGSERVICE_H_

Modified: sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpCreateRuntimeMap.cpp
===================================================================
--- sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpCreateRuntimeMap.cpp	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpCreateRuntimeMap.cpp	2013-05-15 15:35:36 UTC (rev 7495)
@@ -61,6 +61,18 @@
     {
         m_targetMapName = sTargetMapName;
     }
+    m_iconWidth = 16;
+    m_iconHeight = 16;
+    STRING sIconWidth = params->GetParameterValue(MgHttpResourceStrings::reqMappingIconWidth);
+    if (!sIconWidth.empty())
+    {
+        m_iconWidth = MgUtil::StringToInt32(sIconWidth);
+    }
+    STRING sIconHeight = params->GetParameterValue(MgHttpResourceStrings::reqMappingIconHeight);
+    if (!sIconHeight.empty())
+    {
+        m_iconHeight = MgUtil::StringToInt32(sIconHeight);
+    }
 }
 
 /// <summary>
@@ -88,25 +100,6 @@
     if (!m_targetMapName.empty())
         mapName = m_targetMapName;
 
-    byteReader = BuildRuntimeMapXml(mdfId, mapName);
-    // Convert to requested response format, if necessary
-    ProcessFormatConversion(byteReader);
-
-    hResult->SetResultObject(byteReader, byteReader->GetMimeType());
-
-    MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpCreateRuntimeMap.Execute")
-}
-
-MgByteReader* MgHttpCreateRuntimeMap::BuildRuntimeMapXml(MgResourceIdentifier* mdfId, CREFSTRING mapName)
-{
-    Ptr<MgByteReader> byteReader;
-    LayerDefinitionMap layerDefinitionMap;
-    MG_HTTP_HANDLER_TRY()
-
-    Ptr<MgMap> map = new MgMap();
-    Ptr<MgMappingService> mappingService = (MgMappingService*)CreateService(MgServiceType::MappingService);
-    Ptr<MgResourceService> resourceService = (MgResourceService*)CreateService(MgServiceType::ResourceService);
-
     // Create a new session id if we don't have one
     STRING sessionId = m_userInfo->GetMgSessionId();
     if (sessionId.empty())
@@ -118,410 +111,16 @@
         m_userInfo->SetMgSessionId(sessionId);
     }
 
-    // NOTE: We're sticking with the un-written spec of the map name being the name of the map definition id
-    map->Create(resourceService, mdfId, mapName);
-    STRING sStateId = L"Session:";
-    sStateId += sessionId;
-    sStateId += L"//";
-    sStateId += mapName;
-    sStateId += L".";
-    sStateId += MgResourceType::Map;
+    Ptr<MgMappingService> mappingService = (MgMappingService*)CreateService(MgServiceType::MappingService);
+    byteReader = mappingService->CreateRuntimeMap(mdfId, mapName, sessionId, m_iconWidth, m_iconHeight, m_requestDataMask, m_iconLimitPerScaleRange);
+    // Convert to requested response format, if necessary
+    ProcessFormatConversion(byteReader);
 
-    Ptr<MgResourceIdentifier> mapStateId = new MgResourceIdentifier(sStateId);
-    Ptr<MgSelection> sel = new MgSelection(map);
-    sel->Save(resourceService, mapName);
-    map->Save(resourceService, mapStateId);
+    hResult->SetResultObject(byteReader, byteReader->GetMimeType());
 
-    //TODO: Possible future caching opportunity?
-
-    std::string xml;
-    xml.append("<RuntimeMap>\n");
-    // ------------------------------ Site Version ----------------------------------//
-    xml.append("<SiteVersion>");
-    Ptr<MgServerAdmin> serverAdmin = new MgServerAdmin();
-    serverAdmin->Open(m_userInfo);
-    xml.append(MgUtil::WideCharToMultiByte(serverAdmin->GetSiteVersion()));
-    xml.append("</SiteVersion>\n");
-    // ------------------------------ Session ID --------------------------------- //
-    xml.append("<SessionId>");
-    xml.append(MgUtil::WideCharToMultiByte(sessionId));
-    xml.append("</SessionId>\n");
-    // ------------------------------ Map Name --------------------------------- //
-    xml.append("<Name>");
-    xml.append(MgUtil::WideCharToMultiByte(mapName));
-    xml.append("</Name>\n");
-    // ------------------------------ Map Definition ID --------------------------------- //
-    xml.append("<MapDefinition>");
-    xml.append(MgUtil::WideCharToMultiByte(mdfId->ToString()));
-    xml.append("</MapDefinition>\n");
-    // ------------------------------ Background Color ---------------------------------- //
-    xml.append("<BackgroundColor>");
-    xml.append(MgUtil::WideCharToMultiByte(map->GetBackgroundColor()));
-    xml.append("</BackgroundColor>");
-    // ------------------------------ Coordinate System --------------------------------- //
-    xml.append("<CoordinateSystem>\n");
-    xml.append("<Wkt>");
-    STRING srs = map->GetMapSRS();
-    xml.append(MgUtil::WideCharToMultiByte(MgUtil::ReplaceEscapeCharInXml(srs)));
-    xml.append("</Wkt>\n");
-    Ptr<MgCoordinateSystemFactory> fact = new MgCoordinateSystemFactory();
-    std::string sEpsg;
-    std::string sMentor;
-    std::string sMpu;
-    try
-    {
-        Ptr<MgCoordinateSystem> cs = fact->Create(srs);
-        if (!srs.empty())
-            MgUtil::DoubleToString(cs->ConvertCoordinateSystemUnitsToMeters(1.0), sMpu);
-        else
-            sMpu = "1.0";
-        sMentor = MgUtil::WideCharToMultiByte(cs->GetCsCode());
-        INT32 epsg = cs->GetEpsgCode();
-        MgUtil::Int32ToString(epsg, sEpsg);
-    }
-    catch (MgException* ex)
-    {
-        SAFE_RELEASE(ex);
-    }
-    xml.append("<MentorCode>");
-    xml.append(sMentor);
-    xml.append("</MentorCode>\n");
-    xml.append("<EpsgCode>");
-    xml.append(sEpsg);
-    xml.append("</EpsgCode>\n");
-    xml.append("<MetersPerUnit>");
-    xml.append(sMpu);
-    xml.append("</MetersPerUnit>\n");
-    xml.append("</CoordinateSystem>");
-    // ------------------------------ Extents --------------------------------- //
-    std::string sExtents;
-    Ptr<MgEnvelope> extents = map->GetMapExtent();
-    extents->ToXml(sExtents);
-    xml.append("<Extents>\n");
-    xml.append(sExtents);
-    xml.append("</Extents>");
-    // ---------------------- Optional things if requested -------------------- //
-    if ((m_requestDataMask & REQUEST_LAYER_STRUCTURE) == REQUEST_LAYER_STRUCTURE)
-    {
-        //Build our LayerDefinition map for code below that requires it
-        if ((m_requestDataMask & REQUEST_LAYER_ICONS) == REQUEST_LAYER_ICONS)
-        {
-            Ptr<MgStringCollection> layerIds = new MgStringCollection();
-            Ptr<MgLayerCollection> layers = map->GetLayers();
-            for (INT32 i = 0; i < layers->GetCount(); i++)
-            {
-                Ptr<MgLayerBase> layer = layers->GetItem(i);
-                Ptr<MgResourceIdentifier> ldfId = layer->GetLayerDefinition();
-                layerIds->Add(ldfId->ToString());
-            }
-
-            Ptr<MgStringCollection> layerContents = resourceService->GetResourceContents(layerIds, NULL);
-            for (INT32 i = 0; i < layerIds->GetCount(); i++)
-            {
-                STRING ldfId = layerIds->GetItem(i);
-                STRING content = layerContents->GetItem(i);
-                MdfModel::LayerDefinition* ldf = MgLayerBase::GetLayerDefinition(content);
-                layerDefinitionMap[ldfId] = ldf;
-            }
-        }
-
-        // ----------- Some pre-processing before we do groups/layers ------------- //
-        Ptr<MgLayerGroupCollection> groups = map->GetLayerGroups();
-        Ptr<MgLayerCollection> layers = map->GetLayers();
-        for (INT32 i = 0; i < groups->GetCount(); i++)
-        {
-            Ptr<MgLayerGroup> group = groups->GetItem(i);
-            Ptr<MgLayerGroup> parent = group->GetGroup();
-            CreateGroupItem(mappingService, group, parent, xml);
-        }
-        for (INT32 i = 0; i < layers->GetCount(); i++)
-        {
-            Ptr<MgLayerBase> layer = layers->GetItem(i);
-            Ptr<MgLayerGroup> parent = layer->GetGroup();
-            
-            MdfModel::LayerDefinition* layerDef = NULL;
-            Ptr<MgResourceIdentifier> layerid = layer->GetLayerDefinition();
-            LayerDefinitionMap::iterator it = layerDefinitionMap.find(layerid->ToString());
-            if (it != layerDefinitionMap.end())
-                layerDef = it->second;
-
-            CreateLayerItem(mappingService, layer, parent, layerDef, xml);
-        }
-    }
-    // ------------------------ Finite Display Scales (if any) ------------------------- //
-    INT32 fsCount = map->GetFiniteDisplayScaleCount();
-    if (fsCount > 0)
-    {
-        for (INT32 i = 0; i < fsCount; i++)
-        {
-            xml.append("<FiniteDisplayScale>");
-            double dScale = map->GetFiniteDisplayScaleAt(i);
-            std::string sScale;
-            MgUtil::DoubleToString(dScale, sScale);
-            xml.append(sScale);
-            xml.append("</FiniteDisplayScale>\n");
-        }
-    }
-    xml.append("</RuntimeMap>");
-
-    Ptr<MgByteSource> byteSource = new MgByteSource((BYTE_ARRAY_IN)xml.c_str(), (INT32)xml.length());
-    byteSource->SetMimeType(MgMimeType::Xml);
-    byteReader = byteSource->GetReader();
-
-    MG_HTTP_HANDLER_CATCH(L"MgHttpCreateRuntimeMap.BuildRuntimeMapXml")
-
-    //Cleanup our LayerDefinition pointers. Do it here so we don't leak on any exception
-    for (LayerDefinitionMap::iterator it = layerDefinitionMap.begin(); it != layerDefinitionMap.end(); it++)
-    {
-        MdfModel::LayerDefinition* ldf = it->second;
-        delete ldf;
-    }
-    layerDefinitionMap.clear();
-
-    MG_HTTP_HANDLER_THROW()
-
-    return byteReader.Detach();
+    MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpCreateRuntimeMap.Execute")
 }
 
-void MgHttpCreateRuntimeMap::CreateGroupItem(MgMappingService* mappingService, MgLayerGroup* group, MgLayerGroup* parent, std::string& xml)
-{
-    MG_HTTP_HANDLER_TRY()
-
-    STRING groupName = group->GetName();
-    xml.append("<Group>\n");
-    xml.append("<Name>");
-    xml.append(MgUtil::WideCharToMultiByte(groupName));
-    xml.append("</Name>\n");
-    xml.append("<Type>");
-    INT32 gType = group->GetLayerGroupType();
-    std::string sType;
-    MgUtil::Int32ToString(gType, sType);
-    xml.append(sType);
-    xml.append("</Type>\n");
-    xml.append("<LegendLabel>");
-    xml.append(MgUtil::WideCharToMultiByte(MgUtil::ReplaceEscapeCharInXml(group->GetLegendLabel())));
-    xml.append("</LegendLabel>\n");
-    xml.append("<ObjectId>");
-    xml.append(MgUtil::WideCharToMultiByte(group->GetObjectId()));
-    xml.append("</ObjectId>\n");
-    if (NULL != parent)
-    {
-        xml.append("<ParentId>");
-        xml.append(MgUtil::WideCharToMultiByte(parent->GetObjectId()));
-        xml.append("</ParentId>\n");
-    }
-    xml.append("<DisplayInLegend>");
-    xml.append(group->GetDisplayInLegend() ? "true" : "false");
-    xml.append("</DisplayInLegend>\n");
-    xml.append("<ExpandInLegend>");
-    xml.append(group->GetExpandInLegend() ? "true" : "false");
-    xml.append("</ExpandInLegend>\n");
-    xml.append("<Visible>");
-    xml.append(group->GetVisible() ? "true" : "false");
-    xml.append("</Visible>\n");
-    xml.append("<ActuallyVisible>");
-    xml.append(group->IsVisible() ? "true" : "false");
-    xml.append("</ActuallyVisible>\n");
-    xml.append("</Group>");
-
-    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpCreateRuntimeMap.CreateGroupItem")
-}
-
-void MgHttpCreateRuntimeMap::CreateLayerItem(MgMappingService* mappingService, MgLayerBase* layer, MgLayerGroup* parent, MdfModel::LayerDefinition* ldf, std::string& xml)
-{
-    MG_HTTP_HANDLER_TRY()
-
-    xml.append("<Layer>\n");
-    xml.append("<Type>");
-    std::string sLayerType;
-    MgUtil::Int32ToString(layer->GetLayerType(), sLayerType);
-    xml.append(sLayerType);
-    xml.append("</Type>\n");
-    xml.append("<LayerDefinition>");
-    Ptr<MgResourceIdentifier> layerDefId = layer->GetLayerDefinition();
-    STRING ldfId = layerDefId->ToString();
-    xml.append(MgUtil::WideCharToMultiByte(ldfId));
-    xml.append("</LayerDefinition>\n");
-    xml.append("<Name>");
-    xml.append(MgUtil::WideCharToMultiByte(layer->GetName()));
-    xml.append("</Name>\n");
-    xml.append("<LegendLabel>");
-    xml.append(MgUtil::WideCharToMultiByte(MgUtil::ReplaceEscapeCharInXml(layer->GetLegendLabel())));
-    xml.append("</LegendLabel>\n");
-    xml.append("<ObjectId>");
-    xml.append(MgUtil::WideCharToMultiByte(layer->GetObjectId()));
-    xml.append("</ObjectId>\n");
-    if (NULL != parent)
-    {
-        xml.append("<ParentId>");
-        xml.append(MgUtil::WideCharToMultiByte(parent->GetObjectId()));
-        xml.append("</ParentId>\n");
-    }
-    xml.append("<Selectable>");
-    xml.append(layer->GetSelectable() ? "true" : "false");
-    xml.append("</Selectable>\n");
-    xml.append("<DisplayInLegend>");
-    xml.append(layer->GetDisplayInLegend() ? "true" : "false");
-    xml.append("</DisplayInLegend>\n");
-    xml.append("<ExpandInLegend>");
-    xml.append(layer->GetExpandInLegend() ? "true" : "false");
-    xml.append("</ExpandInLegend>\n");
-    xml.append("<Visible>");
-    xml.append(layer->GetVisible() ? "true" : "false");
-    xml.append("</Visible>\n");
-    xml.append("<ActuallyVisible>");
-    xml.append(layer->IsVisible() ? "true" : "false");
-    xml.append("</ActuallyVisible>\n");
-    // ----------------------- Optional things if requested ------------------------- //
-    if ((m_requestDataMask & REQUEST_LAYER_FEATURE_SOURCE) == REQUEST_LAYER_FEATURE_SOURCE)
-    {
-        xml.append("<FeatureSource>\n");
-        xml.append("<ResourceId>");
-        xml.append(MgUtil::WideCharToMultiByte(layer->GetFeatureSourceId()));
-        xml.append("</ResourceId>\n");
-        xml.append("<ClassName>");
-        xml.append(MgUtil::WideCharToMultiByte(layer->GetFeatureClassName()));
-        xml.append("</ClassName>\n");
-        xml.append("<Geometry>");
-        xml.append(MgUtil::WideCharToMultiByte(layer->GetFeatureGeometryName()));
-        xml.append("</Geometry>\n");
-        xml.append("</FeatureSource>\n");
-    }
-    
-    if (NULL != ldf)
-    {
-        MdfModel::VectorLayerDefinition* vl = dynamic_cast<MdfModel::VectorLayerDefinition*>(ldf);
-        if (NULL != vl)
-        {
-            MdfModel::VectorScaleRangeCollection* vsrs = vl->GetScaleRanges();
-            for (INT32 i = 0; i < vsrs->GetCount(); i++)
-            {
-                MdfModel::VectorScaleRange* vsr = vsrs->GetAt(i);
-                xml.append("<ScaleRange>\n");
-                xml.append("<MinScale>");
-                std::string sMinScale;
-                MgUtil::DoubleToString(vsr->GetMinScale(), sMinScale);
-                xml.append(sMinScale);
-                xml.append("</MinScale>\n");
-                xml.append("<MaxScale>");
-                std::string sMaxScale;
-                MgUtil::DoubleToString(vsr->GetMaxScale(), sMaxScale);
-                xml.append(sMaxScale);
-                xml.append("</MaxScale>\n");
-
-                double dScale = (vsr->GetMaxScale() + vsr->GetMinScale()) / 2.0;
-                MdfModel::FeatureTypeStyleCollection* ftsc = vsr->GetFeatureTypeStyles();
-
-                INT32 nIconCount = 0;
-                for (INT32 j = 0; j < ftsc->GetCount(); j++)
-                {
-                    MdfModel::FeatureTypeStyle* fts = ftsc->GetAt(j);
-                    if (fts->IsShowInLegend())
-                    {
-                        MdfModel::RuleCollection* rules = fts->GetRules();
-                        nIconCount += rules->GetCount();
-                    }
-                }
-
-                //This theme will be compressed if we're over the specified limit for this scale range
-                bool bCompress = (nIconCount > m_iconLimitPerScaleRange);
-
-                for (INT32 j = 0; j < ftsc->GetCount(); j++)
-                {
-                    MdfModel::FeatureTypeStyle* fts = ftsc->GetAt(j);
-                    if (!fts->IsShowInLegend())
-                        continue;
-
-                    MdfModel::PointTypeStyle*       pts = dynamic_cast<MdfModel::PointTypeStyle*>(fts);
-                    MdfModel::LineTypeStyle*        lts = dynamic_cast<MdfModel::LineTypeStyle*>(fts);
-                    MdfModel::AreaTypeStyle*        ats = dynamic_cast<MdfModel::AreaTypeStyle*>(fts);
-                    MdfModel::CompositeTypeStyle*   cts = dynamic_cast<MdfModel::CompositeTypeStyle*>(fts);
-                        
-                    INT32 geomType = 0;
-                    if (pts)
-                        geomType = 1;
-                    else if (lts)
-                        geomType = 2;
-                    else if (ats)
-                        geomType = 3;
-                    else if (cts)
-                        geomType = 4;
-                    INT32 catIndex = 0;
-
-                    MdfModel::RuleCollection* rules = fts->GetRules();
-                    for (INT32 r = 0; r < rules->GetCount(); r++)
-                    {
-                        MdfModel::Rule* rule = rules->GetAt(r);
-                        bool bRequestIcon = false;
-                        if (!bCompress)
-                        {
-                            bRequestIcon = true;
-                        }
-                        else //This is a compressed theme
-                        {
-                            bRequestIcon = (r == 0 || r == rules->GetCount() - 1); //Only first and last rule
-                        }
-
-                        xml.append("<Rule>\n");
-                        //GeometryType and ThemeCategory are required so that deferred icon requests can be made
-                        //back to the mapagent, especially if we exceed the icons-per-scale-range limit
-                        xml.append("<GeometryType>");
-                        std::string sGeomType;
-                        MgUtil::Int32ToString(geomType, sGeomType);
-                        xml.append(sGeomType);
-                        xml.append("</GeometryType>\n");
-                        xml.append("<ThemeCategory>");
-                        std::string sThemeCat;
-                        MgUtil::Int32ToString(catIndex, sThemeCat);
-                        xml.append(sThemeCat);
-                        xml.append("</ThemeCategory>\n");
-                        xml.append("<LegendLabel>");
-                        xml.append(MgUtil::WideCharToMultiByte(MgUtil::ReplaceEscapeCharInXml(rule->GetLegendLabel())));
-                        xml.append("</LegendLabel>\n");
-                        xml.append("<Filter>");
-                        xml.append(MgUtil::WideCharToMultiByte(MgUtil::ReplaceEscapeCharInXml(rule->GetFilter())));
-                        xml.append("</Filter>\n");
-                        if (bRequestIcon)
-                        {
-                            xml.append("<Icon>");
-                            //TODO: We should have a batched form of this API
-                            Ptr<MgByteReader> iconReader = mappingService->GenerateLegendImage(layerDefId, dScale, 16, 16, MgImageFormats::Png, geomType, catIndex);
-                            xml.append("<MimeType>");
-                            //BUG? No mime type in the MgByteReader
-                            xml.append(MgUtil::WideCharToMultiByte(MgMimeType::Png));
-                            //xml.append(MgUtil::WideCharToMultiByte(iconReader->GetMimeType()));
-                            xml.append("</MimeType>\n");
-                            xml.append("<Content>");
-                            Ptr<MgByteSink> sink = new MgByteSink(iconReader);
-                            Ptr<MgByte> bytes = sink->ToBuffer();
-                            Ptr<MgMemoryStreamHelper> streamHelper = new MgMemoryStreamHelper((INT8*) bytes->Bytes(), bytes->GetLength(), false);
-                            std::string b64 = streamHelper->ToBase64();
-                            xml.append(b64);
-                            xml.append("</Content>\n");
-                            xml.append("</Icon>");
-                        }
-                        xml.append("</Rule>\n");
-
-                        catIndex++;
-                    }
-                }
-
-                xml.append("</ScaleRange>\n");
-            }
-        }
-        else
-        {
-            xml.append("<ScaleRange/>");
-        }
-    }
-    else
-        xml.append("<ScaleRange/>");
-
-    xml.append("</Layer>");
-
-    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpCreateRuntimeMap.CreateLayerItem")
-}
-
 /// <summary>
 /// This method is responsible for checking if
 /// a valid version was given

Modified: sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpCreateRuntimeMap.h
===================================================================
--- sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpCreateRuntimeMap.h	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpCreateRuntimeMap.h	2013-05-15 15:35:36 UTC (rev 7495)
@@ -61,12 +61,10 @@
     virtual void ValidateOperationVersion();
 
 private:
-    MgByteReader* BuildRuntimeMapXml(MgResourceIdentifier* mdfId, CREFSTRING mapName);
-    void CreateGroupItem(MgMappingService* mappingService, MgLayerGroup* group, MgLayerGroup* parent, std::string& xml);
-    void CreateLayerItem(MgMappingService* mappingService, MgLayerBase* layer, MgLayerGroup* parent, MdfModel::LayerDefinition* ldf, std::string& xml);
-
     STRING m_targetMapName;
     STRING m_mapDefinition;
+    INT32 m_iconWidth;
+    INT32 m_iconHeight;
     INT32 m_requestDataMask;
     INT32 m_iconLimitPerScaleRange;
 };

Modified: sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpResourceStrings.cpp
===================================================================
--- sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpResourceStrings.cpp	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpResourceStrings.cpp	2013-05-15 15:35:36 UTC (rev 7495)
@@ -220,6 +220,8 @@
 const STRING MgHttpResourceStrings::reqMappingRequestedFeatures = L"REQUESTEDFEATURES";
 const STRING MgHttpResourceStrings::reqMappingIconsPerScaleRange = L"ICONSPERSCALERANGE";
 const STRING MgHttpResourceStrings::reqMappingTargetMapName = L"TARGETMAPNAME";
+const STRING MgHttpResourceStrings::reqMappingIconWidth = L"ICONWIDTH";
+const STRING MgHttpResourceStrings::reqMappingIconHeight = L"ICONHEIGHT";
 
 // Predefined Rendering Service Request Parameters
 const STRING MgHttpResourceStrings::reqRenderingMapDefinition = L"MAPDEFINITION";

Modified: sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpResourceStrings.h
===================================================================
--- sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpResourceStrings.h	2013-05-15 11:17:27 UTC (rev 7494)
+++ sandbox/jng/createruntimemap/Web/src/HttpHandler/HttpResourceStrings.h	2013-05-15 15:35:36 UTC (rev 7495)
@@ -156,6 +156,8 @@
     static const STRING reqMappingRequestedFeatures;
     static const STRING reqMappingIconsPerScaleRange;
     static const STRING reqMappingTargetMapName;
+    static const STRING reqMappingIconWidth;
+    static const STRING reqMappingIconHeight;
 
     // PREDEFINED RENDERING REQUEST PARAMETERS
     static const STRING reqRenderingMapDefinition;



More information about the mapguide-commits mailing list