Changes between Initial Version and Version 1 of MapGuideRfc143


Ignore:
Timestamp:
Jun 30, 2014, 10:14:14 AM (10 years ago)
Author:
jng
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • MapGuideRfc143

    v1 v1  
     1
     2= !MapGuide RFC 143 - Convenience APIs =
     3
     4This page contains a change request (RFC) for the !MapGuide Open Source project.
     5More !MapGuide RFCs can be found on the [wiki:MapGuideRfcs RFCs] page.
     6
     7
     8== Status ==
     9
     10||RFC Template Version||(1.0)||
     11||Submission Date||1 July 2014||
     12||Last Modified||||
     13||Author||Jackie Ng||
     14||RFC Status||||
     15||Implementation Status||||
     16||Proposed Milestone||||
     17||Assigned PSC guide(s)||(when determined)||
     18||'''Voting History'''||(vote date)||
     19||+1||||
     20||+0||||
     21||-0||||
     22||-1||||
     23||no vote|| ||
     24
     25== Overview ==
     26
     27This RFC proposes include various convenience APIs for improved developer experience
     28
     29== Motivation ==
     30
     31[wiki:MapGuideRfc9 MapGuide RFC 9] introduced some useful convenience APIs for common developer patterns in MapGuide applications. However, there are several cases there are still lots of boilerplate code involved in achieving the desired result:
     32
     33 * Inserting/Updating/Deleting features
     34 * Determining and rendering layer style icons
     35 * Layer-bound operations that still require using MgFeatureService using the layer's feature source and class name/geometry
     36
     37In addition, there are several internal APIs that have value being exposed for external/public consumption
     38
     39== Proposed Solution ==
     40
     41=== Inserting/Updating/Deleting features ===
     42
     43Inserting/Updating/Deleting features using the existing UpdateFeatures() API is a verbose and complex affair, even if the developer only wants to do one of the actions (inserting, updating or deleting and not any combination thereof).
     44
     45In addition to the complex setup process to use this API, another common problem that can easily be overlooked is the need to actually process the return value of this API:
     46
     47 * Result has to be checked for any feature properties (that contain MgFeatureReader results for insert operations)
     48 * Result has to be checked for any string properties (that contain FDO exception messages for any operation when UpdateFeatures() is called without transaction support. Even more confusing, when transactions are used the application has to be ready to catch any exceptions as they won't be serialized out to string properties in the result)
     49
     50Failure to do this may cause busy resource errors (due to un-closed MgFeatureReader objects) and unspecified application behaviour (due to failing to handle FDO errors).
     51
     52Here's a piece of sample code to insert a new feature, demonstrating the verbosity of this current API:
     53
     54{{{
     55MgResourceIdentifier fsId = new MgResourceIdentifier("Library://Test.FeatureSource");
     56MgWktReaderWriter wktRw = new MgWktReaderWriter();
     57MgAgfReaderWriter agfRw = new MgAgfReaderWriter();
     58MgGeometry geom = wktRw.Read("POINT(1 1)");
     59MgByteReader agf = agfRw.Write(geom);
     60
     61//Prepare insert values
     62MgPropertyCollection insertVals = new MgPropertyCollection();
     63MgStringProperty nameVal = new MgStringProperty("Name", "Hello World");
     64MgGeometryProperty geomVal = new MgGeometryProeprty("Geometry", agf);
     65insertVals.Add(nameVal);
     66insertVals.Add(geomVal);
     67
     68//Prepare command collection for UpdateFeatures
     69MgFeatureCommandCollection commands = new MgFeatureCommandCollection();
     70MgInsertFeatures insertCmd = new MgInsertFeatures("Default:Test", insertVals);
     71commands.Add(insertCmd);
     72
     73//Call API and process result (important!)
     74MgPropertyCollection result = featureService.UpdateFeatures(fsId, commands, false);
     75for (int i = 0; i < result.GetCount(); i++)
     76{
     77    MgProperty prop = result.GetItem(i);
     78    if (prop.GetPropertyType() == MgPropertyType::Feature) //Insert result
     79    {
     80        MgFeatureProperty fp = (MgFeatureProperty)prop;
     81        //Must close the reader inside to prevent busy resource errors
     82        MgFeatureReader reader = fp.GetValue();
     83        reader.Close();
     84    }
     85    else if (prop.GetPropertyType() ==- MgPropertyType::String) //FDO error in non-transactional mode
     86    {
     87        MgStringProperty sp = (MgStringProperty)prop;
     88        String fdoError = sp.GetValue();
     89        //Handle this error
     90    }
     91}
     92}}}
     93
     94As you can see, this type of code is a lot of boilerplate for just inserting features.
     95
     96For this RFC, we will add convenience APIs to MgFeatureService and MgLayerBase to do individual insert/update/delete operations instead of a one-size-fits-all API that we currently have:
     97
     98{{{
     99class MG_PLATFORMBASE_API MgFeatureService : public MgService
     100{
     101PUBLISHED_API:
     102    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     103    /// \brief
     104    /// Inserts a new feature into the specified feature class of the specified Feature Source
     105    ///
     106    /// <!-- Syntax in .Net, Java, and PHP -->
     107    /// \htmlinclude DotNetSyntaxTop.html
     108    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection propertyValues);
     109    /// \htmlinclude SyntaxBottom.html
     110    /// \htmlinclude JavaSyntaxTop.html
     111    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues);
     112    /// \htmlinclude SyntaxBottom.html
     113    /// \htmlinclude PHPSyntaxTop.html
     114    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues);
     115    /// \htmlinclude SyntaxBottom.html
     116    ///
     117    /// \param resource (MgResourceIdentifier)
     118    /// A resource identifier for the feature
     119    /// source.
     120    /// \param className (String/string)
     121    /// The name of the feature class on which
     122    /// the insert operation is performed.
     123    /// \param propertyValues (MgPropertyCollection)
     124    /// The collection of property values to insert
     125    ///
     126    /// \return
     127    /// Returns a feature reader object that contains the set of properties
     128    /// inserted into the datastore by the insert command.
     129    ///
     130    /// \remarks
     131    /// Remember to close any feature readers returned by this method, even if you don't intend
     132    /// to do anything with them
     133    ///
     134    /// \exception MgFeatureServiceException
     135    /// \exception MgInvalidArgumentException
     136    /// \exception MgInvalidOperationException
     137    /// \exception MgFdoException
     138    ///
     139    /// \since 3.0
     140    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
     141                                            CREFSTRING className,
     142                                            MgPropertyCollection* propertyValues) = 0;
     143
     144    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     145    /// \brief
     146    /// Inserts a new feature into the specified feature class of the specified Feature Source
     147    ///
     148    /// <!-- Syntax in .Net, Java, and PHP -->
     149    /// \htmlinclude DotNetSyntaxTop.html
     150    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection propertyValues, MgTransaction trans);
     151    /// \htmlinclude SyntaxBottom.html
     152    /// \htmlinclude JavaSyntaxTop.html
     153    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues, MgTransaction trans);
     154    /// \htmlinclude SyntaxBottom.html
     155    /// \htmlinclude PHPSyntaxTop.html
     156    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection propertyValues, MgTransaction trans);
     157    /// \htmlinclude SyntaxBottom.html
     158    ///
     159    /// \param resource (MgResourceIdentifier)
     160    /// A resource identifier for the feature
     161    /// source.
     162    /// \param className (String/string)
     163    /// The name of the feature class on which
     164    /// the insert operation is performed.
     165    /// \param propertyValues (MgPropertyCollection)
     166    /// The collection of property values to insert
     167    /// \param trans (MgTransaction)
     168    /// The transaction to execute this operation under
     169    ///
     170    /// \return
     171    /// Returns a feature reader object that contains the set of properties
     172    /// inserted into the datastore by the insert command.
     173    ///
     174    /// \remarks
     175    /// Remember to close any feature readers returned by this method, even if you don't intend
     176    /// to do anything with them
     177    ///
     178    /// \exception MgFeatureServiceException
     179    /// \exception MgInvalidArgumentException
     180    /// \exception MgInvalidOperationException
     181    /// \exception MgFdoException
     182    ///
     183    /// \since 3.0
     184    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
     185                                            CREFSTRING className,
     186                                            MgPropertyCollection* propertyValues,
     187                                            MgTransaction* trans) = 0;
     188
     189    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     190    /// \brief
     191    /// Inserts a set of new features into the specified feature class of the specified Feature Source
     192    ///
     193    /// <!-- Syntax in .Net, Java, and PHP -->
     194    /// \htmlinclude DotNetSyntaxTop.html
     195    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgBatchPropertyCollection batchPropertyValues);
     196    /// \htmlinclude SyntaxBottom.html
     197    /// \htmlinclude JavaSyntaxTop.html
     198    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues);
     199    /// \htmlinclude SyntaxBottom.html
     200    /// \htmlinclude PHPSyntaxTop.html
     201    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues);
     202    /// \htmlinclude SyntaxBottom.html
     203    ///
     204    /// \param resource (MgResourceIdentifier)
     205    /// A resource identifier for the feature
     206    /// source.
     207    /// \param className (String/string)
     208    /// The name of the feature class on which
     209    /// the insert operation is performed.
     210    /// \param batchPropertyValues (MgBatchPropertyCollection)
     211    /// The collection of property values to insert. Each MgPropertyCollection within
     212    /// this collection represents property values for a single feature to insert
     213    ///
     214    /// \return
     215    /// Returns a feature reader object that contains the set of properties
     216    /// inserted into the datastore by the insert command.
     217    ///
     218    /// \remarks
     219    /// Remember to close any feature readers returned by this method, even if you don't intend
     220    /// to do anything with them
     221    ///
     222    /// \exception MgFeatureServiceException
     223    /// \exception MgInvalidArgumentException
     224    /// \exception MgInvalidOperationException
     225    /// \exception MgFdoException
     226    ///
     227    /// \since 3.0
     228    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
     229                                            CREFSTRING className,
     230                                            MgBatchPropertyCollection* batchPropertyValues) = 0;
     231
     232    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     233    /// \brief
     234    /// Inserts a set of new features into the specified feature class of the specified Feature Source
     235    ///
     236    /// <!-- Syntax in .Net, Java, and PHP -->
     237    /// \htmlinclude DotNetSyntaxTop.html
     238    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, string className, MgBatchPropertyCollection batchPropertyValues, MgTransaction trans);
     239    /// \htmlinclude SyntaxBottom.html
     240    /// \htmlinclude JavaSyntaxTop.html
     241    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues, MgTransaction trans);
     242    /// \htmlinclude SyntaxBottom.html
     243    /// \htmlinclude PHPSyntaxTop.html
     244    /// virtual MgFeatureReader InsertFeatures(MgResourceIdentifier resource, String className, MgBatchPropertyCollection batchPropertyValues, MgTransaction trans);
     245    /// \htmlinclude SyntaxBottom.html
     246    ///
     247    /// \param resource (MgResourceIdentifier)
     248    /// A resource identifier for the feature
     249    /// source.
     250    /// \param className (String/string)
     251    /// The name of the feature class on which
     252    /// the insert operation is performed.
     253    /// \param batchPropertyValues (MgBatchPropertyCollection)
     254    /// The collection of property values to insert. Each MgPropertyCollection within
     255    /// this collection represents property values for a single feature to insert
     256    /// \param trans (MgTransaction)
     257    /// The transaction to execute this operation under
     258    ///
     259    /// \return
     260    /// Returns a feature reader object that contains the set of properties
     261    /// inserted into the datastore by the insert command.
     262    ///
     263    /// \remarks
     264    /// Remember to close any feature readers returned by this method, even if you don't intend
     265    /// to do anything with them
     266    ///
     267    /// \exception MgFeatureServiceException
     268    /// \exception MgInvalidArgumentException
     269    /// \exception MgInvalidOperationException
     270    /// \exception MgFdoException
     271    ///
     272    /// \since 3.0
     273    virtual MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource,
     274                                            CREFSTRING className,
     275                                            MgBatchPropertyCollection* batchPropertyValues,
     276                                            MgTransaction* trans) = 0;
     277
     278    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     279    /// \brief
     280    /// Updates all features that match the given filter with the specified property values
     281    ///
     282    /// <!-- Syntax in .Net, Java, and PHP -->
     283    /// \htmlinclude DotNetSyntaxTop.html
     284    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection properties, string filter);
     285    /// \htmlinclude SyntaxBottom.html
     286    /// \htmlinclude JavaSyntaxTop.html
     287    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter);
     288    /// \htmlinclude SyntaxBottom.html
     289    /// \htmlinclude PHPSyntaxTop.html
     290    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter);
     291    /// \htmlinclude SyntaxBottom.html
     292    ///
     293    /// \param resource (MgResourceIdentifier)
     294    /// A resource identifier for the feature
     295    /// source.
     296    /// \param className (String/string)
     297    /// The name of the feature class on which
     298    /// the update operation is performed.
     299    /// \param properties (MgBatchPropertyCollection)
     300    /// The property values to update matching features with
     301    /// \param filter (String/string)
     302    /// The FDO filter string that detemines what features will be updated
     303    ///
     304    /// \return
     305    /// Returns the number of features updated by this operation
     306    ///
     307    /// \exception MgFeatureServiceException
     308    /// \exception MgInvalidArgumentException
     309    /// \exception MgInvalidOperationException
     310    /// \exception MgFdoException
     311    ///
     312    /// \since 3.0
     313    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource,
     314                                         CREFSTRING className,
     315                                         MgPropertyCollection* properties,
     316                                         CREFSTRING filter) = 0;
     317
     318    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     319    /// \brief
     320    /// Updates all features that match the given filter with the specified property values
     321    ///
     322    /// <!-- Syntax in .Net, Java, and PHP -->
     323    /// \htmlinclude DotNetSyntaxTop.html
     324    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, string className, MgPropertyCollection properties, string filter, MgTransaction trans);
     325    /// \htmlinclude SyntaxBottom.html
     326    /// \htmlinclude JavaSyntaxTop.html
     327    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter, MgTransaction trans);
     328    /// \htmlinclude SyntaxBottom.html
     329    /// \htmlinclude PHPSyntaxTop.html
     330    /// virtual int UpdateMatchingFeatures(MgResourceIdentifier resource, String className, MgPropertyCollection properties, String filter, MgTransaction trans);
     331    /// \htmlinclude SyntaxBottom.html
     332    ///
     333    /// \param resource (MgResourceIdentifier)
     334    /// A resource identifier for the feature
     335    /// source.
     336    /// \param className (String/string)
     337    /// The name of the feature class on which
     338    /// the update operation is performed.
     339    /// \param properties (MgBatchPropertyCollection)
     340    /// The property values to update matching features with
     341    /// \param filter (String/string)
     342    /// The FDO filter string that detemines what features will be updated
     343    /// \param trans (MgTransaction)
     344    /// The transaction to execute this operation under
     345    ///
     346    /// \return
     347    /// Returns the number of features updated by this operation
     348    ///
     349    /// \exception MgFeatureServiceException
     350    /// \exception MgInvalidArgumentException
     351    /// \exception MgInvalidOperationException
     352    /// \exception MgFdoException
     353    ///
     354    /// \since 3.0
     355    virtual INT32 UpdateMatchingFeatures(MgResourceIdentifier* resource,
     356                                         CREFSTRING className,
     357                                         MgPropertyCollection* properties,
     358                                         CREFSTRING filter,
     359                                         MgTransaction* trans) = 0;
     360
     361    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     362    /// \brief
     363    /// Deletes all features that match the given filter
     364    ///
     365    /// <!-- Syntax in .Net, Java, and PHP -->
     366    /// \htmlinclude DotNetSyntaxTop.html
     367    /// virtual int DeleteFeatures(MgResourceIdentifier resource, string className, string filter);
     368    /// \htmlinclude SyntaxBottom.html
     369    /// \htmlinclude JavaSyntaxTop.html
     370    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter);
     371    /// \htmlinclude SyntaxBottom.html
     372    /// \htmlinclude PHPSyntaxTop.html
     373    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter);
     374    /// \htmlinclude SyntaxBottom.html
     375    ///
     376    /// \param resource (MgResourceIdentifier)
     377    /// A resource identifier for the feature
     378    /// source.
     379    /// \param className (String/string)
     380    /// The name of the feature class on which
     381    /// the delete operation is performed.
     382    /// \param filter (String/string)
     383    /// The FDO filter string that detemines what features will be deleted
     384    ///
     385    /// \return
     386    /// Returns the number of features deleted by this operation
     387    ///
     388    /// \exception MgFeatureServiceException
     389    /// \exception MgInvalidArgumentException
     390    /// \exception MgInvalidOperationException
     391    /// \exception MgFdoException
     392    ///
     393    /// \since 3.0
     394    virtual INT32 DeleteFeatures(MgResourceIdentifier* resource,
     395                                 CREFSTRING className,
     396                                 CREFSTRING filter) = 0;
     397
     398    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     399    /// \brief
     400    /// Deletes all features that match the given filter
     401    ///
     402    /// <!-- Syntax in .Net, Java, and PHP -->
     403    /// \htmlinclude DotNetSyntaxTop.html
     404    /// virtual int DeleteFeatures(MgResourceIdentifier resource, string className, string filter, MgTransaction trans);
     405    /// \htmlinclude SyntaxBottom.html
     406    /// \htmlinclude JavaSyntaxTop.html
     407    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter, MgTransaction trans);
     408    /// \htmlinclude SyntaxBottom.html
     409    /// \htmlinclude PHPSyntaxTop.html
     410    /// virtual int DeleteFeatures(MgResourceIdentifier resource, String className, String filter, MgTransaction trans);
     411    /// \htmlinclude SyntaxBottom.html
     412    ///
     413    /// \param resource (MgResourceIdentifier)
     414    /// A resource identifier for the feature
     415    /// source.
     416    /// \param className (String/string)
     417    /// The name of the feature class on which
     418    /// the delete operation is performed.
     419    /// \param filter (String/string)
     420    /// The FDO filter string that detemines what features will be deleted
     421    /// \param trans (MgTransaction)
     422    /// The transaction to execute this operation under
     423    ///
     424    /// \return
     425    /// Returns the number of features deleted by this operation
     426    ///
     427    /// \exception MgFeatureServiceException
     428    /// \exception MgInvalidArgumentException
     429    /// \exception MgInvalidOperationException
     430    /// \exception MgFdoException
     431    ///
     432    /// \since 3.0
     433    virtual INT32 DeleteFeatures(MgResourceIdentifier* resource,
     434                                 CREFSTRING className,
     435                                 CREFSTRING filter,
     436                                 MgTransaction* trans) = 0;
     437};
     438}}}
     439{{{
     440class MG_PLATFORMBASE_API MgLayerBase : public MgNamedSerializable
     441{
     442PUBLISHED_API:
     443    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     444    /// \brief
     445    /// Inserts a new feature into the specified feature class of the specified Feature Source
     446    ///
     447    /// <!-- Syntax in .Net, Java, and PHP -->
     448    /// \htmlinclude DotNetSyntaxTop.html
     449    /// virtual MgFeatureReader InsertFeatures(MgPropertyCollection properties);
     450    /// \htmlinclude SyntaxBottom.html
     451    /// \htmlinclude JavaSyntaxTop.html
     452    /// virtual MgFeatureReader InsertFeatures(MgPropertyCollection properties);
     453    /// \htmlinclude SyntaxBottom.html
     454    /// \htmlinclude PHPSyntaxTop.html
     455    /// virtual MgFeatureReader InsertFeatures(MgPropertyCollection properties);
     456    /// \htmlinclude SyntaxBottom.html
     457    ///
     458    /// \param properties (MgPropertyCollection)
     459    /// The collection of property values to insert
     460    ///
     461    /// \return
     462    /// Returns a feature reader object that contains the set of properties
     463    /// inserted into the datastore by the insert command.
     464    ///
     465    /// \remarks
     466    /// Transactions will be used internally if the provider supports them.
     467    /// Remember to close any feature readers returned by this method, even if you don't intend
     468    /// to do anything with them
     469    ///
     470    /// \exception MgFeatureServiceException
     471    /// \exception MgInvalidArgumentException
     472    /// \exception MgInvalidOperationException
     473    /// \exception MgFdoException
     474    ///
     475    /// \since 3.0
     476    virtual MgFeatureReader* InsertFeatures(MgPropertyCollection* properties);
     477
     478    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     479    /// \brief
     480    /// Inserts a set of new features into the specified feature class of the specified Feature Source
     481    ///
     482    /// <!-- Syntax in .Net, Java, and PHP -->
     483    /// \htmlinclude DotNetSyntaxTop.html
     484    /// virtual MgFeatureReader InsertFeatures(MgBatchPropertyCollection properties);
     485    /// \htmlinclude SyntaxBottom.html
     486    /// \htmlinclude JavaSyntaxTop.html
     487    /// virtual MgFeatureReader InsertFeatures(MgBatchPropertyCollection properties);
     488    /// \htmlinclude SyntaxBottom.html
     489    /// \htmlinclude PHPSyntaxTop.html
     490    /// virtual MgFeatureReader InsertFeatures(MgBatchPropertyCollection properties);
     491    /// \htmlinclude SyntaxBottom.html
     492    ///
     493    /// \param properties (MgBatchPropertyCollection)
     494    /// The collection of property values to insert. Each MgPropertyCollection within
     495    /// this collection represents property values for a single feature to insert
     496    ///
     497    /// \return
     498    /// Returns a feature reader object that contains the set of properties
     499    /// inserted into the datastore by the insert command.
     500    ///
     501    /// \remarks
     502    /// Transactions will be used internally if the provider supports them.
     503    /// Remember to close any feature readers returned by this method, even if you don't intend
     504    /// to do anything with them
     505    ///
     506    /// \exception MgFeatureServiceException
     507    /// \exception MgInvalidArgumentException
     508    /// \exception MgInvalidOperationException
     509    /// \exception MgFdoException
     510    ///
     511    /// \since 3.0
     512    virtual MgFeatureReader* InsertFeatures(MgBatchPropertyCollection* properties);
     513
     514    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     515    /// \brief
     516    /// Updates all features that match the given filter with the specified property values
     517    ///
     518    /// \remarks
     519    /// Transactions will be used internally if the provider supports them
     520    ///
     521    /// <!-- Syntax in .Net, Java, and PHP -->
     522    /// \htmlinclude DotNetSyntaxTop.html
     523    /// virtual int UpdateMatchingFeatures(MgPropertyCollection properties, string filter);
     524    /// \htmlinclude SyntaxBottom.html
     525    /// \htmlinclude JavaSyntaxTop.html
     526    /// virtual int UpdateMatchingFeatures(MgPropertyCollection properties, String filter);
     527    /// \htmlinclude SyntaxBottom.html
     528    /// \htmlinclude PHPSyntaxTop.html
     529    /// virtual int UpdateMatchingFeatures(MgPropertyCollection properties, String filter);
     530    /// \htmlinclude SyntaxBottom.html
     531    ///
     532    /// \param properties (MgBatchPropertyCollection)
     533    /// The property values to update matching features with
     534    /// \param filter (String/string)
     535    /// The FDO filter string that detemines what features will be updated
     536    ///
     537    /// \return
     538    /// Returns the number of features updated by this operation
     539    ///
     540    /// \exception MgFeatureServiceException
     541    /// \exception MgInvalidArgumentException
     542    /// \exception MgInvalidOperationException
     543    /// \exception MgFdoException
     544    ///
     545    /// \since 3.0
     546    virtual INT32 UpdateMatchingFeatures(MgPropertyCollection* properties, CREFSTRING filter);
     547
     548    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     549    /// \brief
     550    /// Deletes all features that match the given filter
     551    ///
     552    /// \remarks
     553    /// Transactions will be used internally if the provider supports them
     554    ///
     555    /// <!-- Syntax in .Net, Java, and PHP -->
     556    /// \htmlinclude DotNetSyntaxTop.html
     557    /// virtual int DeleteFeatures(string filter);
     558    /// \htmlinclude SyntaxBottom.html
     559    /// \htmlinclude JavaSyntaxTop.html
     560    /// virtual int DeleteFeatures(String filter);
     561    /// \htmlinclude SyntaxBottom.html
     562    /// \htmlinclude PHPSyntaxTop.html
     563    /// virtual int DeleteFeatures(String filter);
     564    /// \htmlinclude SyntaxBottom.html
     565    ///
     566    /// \param filter (String/string)
     567    /// The FDO filter string that detemines what features will be deleted
     568    ///
     569    /// \return
     570    /// Returns the number of features deleted by this operation
     571    ///
     572    /// \exception MgFeatureServiceException
     573    /// \exception MgInvalidArgumentException
     574    /// \exception MgInvalidOperationException
     575    /// \exception MgFdoException
     576    ///
     577    /// \since 3.0
     578    virtual INT32 DeleteFeatures(CREFSTRING filter);
     579};
     580}}}
     581
     582With these convenience APIs, the above example for inserting features now becomes:
     583
     584{{{
     585MgResourceIdentifier fsId = new MgResourceIdentifier("Library://Test.FeatureSource");
     586MgWktReaderWriter wktRw = new MgWktReaderWriter();
     587MgAgfReaderWriter agfRw = new MgAgfReaderWriter();
     588MgGeometry geom = wktRw.Read("POINT(1 1)");
     589MgByteReader agf = agfRw.Write(geom);
     590
     591//Prepare insert values
     592MgPropertyCollection insertVals = new MgPropertyCollection();
     593MgStringProperty nameVal = new MgStringProperty("Name", "Hello World");
     594MgGeometryProperty geomVal = new MgGeometryProeprty("Geometry", agf);
     595insertVals.Add(nameVal);
     596insertVals.Add(geomVal);
     597
     598//Call the API
     599try
     600{
     601    MgFeatureReader result = featureService.InsertFeatures(fsId, "Default:Test", insertVals);
     602    result.Close();
     603}
     604catch (MgFdoException ex) //Transactions or not, an exception will be thrown on any FDO error
     605{
     606    //Handle insert error
     607}
     608}}}
     609
     610For updating/deleting features, you will see similar reductions in code using these convenience APIs
     611
     612=== Rendering layer style icons ===
     613
     614The GenerateLegendImage() API of MgRenderingService currently requires you to manually process the XML of the Layer Definition of interest in order to determine the correct parameters for geomType and themeCategory. This results in lots of boilerplate code for unnecessary XML processing. Additional boilerplate is required when dealing with composite styles as you need to calculate the correct offset values for themeCategory in order to generate the correct icon.
     615
     616For this RFC, we'll introduce several APIs to MgLayer to simplify this:
     617
     618{{{
     619class MG_MAPGUIDE_API MgLayer : public MgLayerBase
     620{
     621PUBLISHED_API:
     622    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     623    /// \brief
     624    /// Gets the list of geometry type styles for this layer at the map's current scale. Returns NULL if there are no applicable geometry types
     625    ///
     626    /// <!-- Syntax in .Net, Java, and PHP -->
     627    /// \htmlinclude DotNetSyntaxTop.html
     628    /// virtual MgIntCollection GetGeometryTypeStyles();
     629    /// \htmlinclude SyntaxBottom.html
     630    /// \htmlinclude JavaSyntaxTop.html
     631    /// virtual MgIntCollection GetGeometryTypeStyles();
     632    /// \htmlinclude SyntaxBottom.html
     633    /// \htmlinclude PHPSyntaxTop.html
     634    /// virtual MgIntCollection GetGeometryTypeStyles();
     635    /// \htmlinclude SyntaxBottom.html
     636    ///
     637    /// \remarks
     638    /// The map's current scale is used to determine what scale range in the layer definition to search for.
     639    /// For a scale range with multiple composite styles, multiple instances of (4 = composite) will be in the resulting collection
     640    ///
     641    /// \return
     642    /// The list of geometry type styles for this layer at the map's current scale. Returns NULL if there are no applicable geometry types
     643    ///
     644    /// \since 3.0
     645    MgIntCollection* GetGeometryTypeStyles();
     646
     647    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     648    /// \brief
     649    /// Gets the number of theme categories for this layer at the map's current scale for the given geometry type style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
     650    ///
     651    /// <!-- Syntax in .Net, Java, and PHP -->
     652    /// \htmlinclude DotNetSyntaxTop.html
     653    /// virtual int GetThemeCategoryCount(int geomType);
     654    /// \htmlinclude SyntaxBottom.html
     655    /// \htmlinclude JavaSyntaxTop.html
     656    /// virtual int GetThemeCategoryCount(int geomType);
     657    /// \htmlinclude SyntaxBottom.html
     658    /// \htmlinclude PHPSyntaxTop.html
     659    /// virtual int GetThemeCategoryCount(int geomType);
     660    /// \htmlinclude SyntaxBottom.html
     661    ///
     662    /// \param geomType (int)
     663    /// The geometry type
     664    ///
     665    /// \remarks
     666    /// The map's current scale is used to determine what scale range in the layer definition to search for.
     667    /// When geomType = 4, it will only count the number of the theme categories for the first composite style it finds. For a scale range
     668    /// with multiple composite type styles, you should use GetCompositeThemeCategoryCount() instead
     669    ///
     670    /// \return
     671    /// The number of theme categories for this layer at the map's current scale for the given geometry type style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
     672    ///
     673    /// \since 3.0
     674    INT32 GetThemeCategoryCount(INT32 geomType);
     675
     676    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     677    /// \brief
     678    /// Gets the number of composite theme categories for this layer at the map's current scale for the given composite style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
     679    ///
     680    /// <!-- Syntax in .Net, Java, and PHP -->
     681    /// \htmlinclude DotNetSyntaxTop.html
     682    /// virtual int GetThemeCategoryCount(double scale, int geomType);
     683    /// \htmlinclude SyntaxBottom.html
     684    /// \htmlinclude JavaSyntaxTop.html
     685    /// virtual int GetThemeCategoryCount(double scale, int geomType);
     686    /// \htmlinclude SyntaxBottom.html
     687    /// \htmlinclude PHPSyntaxTop.html
     688    /// virtual int GetThemeCategoryCount(double scale, int geomType);
     689    /// \htmlinclude SyntaxBottom.html
     690    ///
     691    /// \param compositeOffset (int)
     692    /// The zero-based index denoting the particular composite style to count from. 0 = 1st composite style, 1 = 2nd composite style
     693    ///
     694    /// \return
     695    /// The number of theme categories for this layer at the map's current scale for the given composite style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
     696    ///
     697    /// \since 3.0
     698    INT32 GetCompositeThemeCategoryCount(INT32 compositeOffset);
     699
     700    ////////////////////////////////////////////////////////////////////////////////
     701    /// \brief
     702    /// Returns the legend image for the specified geometry type and theme category
     703    ///
     704    /// <!-- Syntax in .Net, Java, and PHP -->
     705    /// \htmlinclude DotNetSyntaxTop.html
     706    /// virtual MgByteReader GenerateLegendImage(int width, int height, string format, int geomType, int themeCategory);
     707    /// \htmlinclude SyntaxBottom.html
     708    /// \htmlinclude JavaSyntaxTop.html
     709    /// virtual MgByteReader GenerateLegendImage(int width, int height, String format, int geomType, int themeCategory);
     710    /// \htmlinclude SyntaxBottom.html
     711    /// \htmlinclude PHPSyntaxTop.html
     712    /// virtual MgByteReader GenerateLegendImage(int width, int height, string format, int geomType, int themeCategory);
     713    /// \htmlinclude SyntaxBottom.html
     714    ///
     715    /// \param resource (MgResourceIdentifier)
     716    /// Input
     717    /// MgResourceIdentifier object identifying the layer definition resource.
     718    /// \param scale (double)
     719    /// Input
     720    /// The scale at which the symbolization is requested.
     721    /// \param width (int)
     722    /// Input
     723    /// The requested image width in pixels.
     724    /// \param height (int)
     725    /// Input
     726    /// The requested image height in pixels.
     727    /// \param format (String/string)
     728    /// Input
     729    /// Image format, from MgImageFormats. Example: PNG, JPG, PNG8, etc
     730    /// \param geomType (int)
     731    /// Input
     732    /// The type of symbolization required: 1=Point, 2=Line, 3=Area, 4=Composite
     733    /// \param themeCategory (int)
     734    /// Input
     735    /// The value indicating which theme category swatch to return.
     736    /// Used when there is a theme defined at this scale. An exception will be
     737    /// thrown if a requested them category doesn't exist.
     738    ///
     739    /// \remarks
     740    /// The map's current scale is used to determine what scale range in the layer definition to search for
     741    ///
     742    /// \return
     743    /// Returns a stream representing the legend image.
     744    /// The default returned image format will be PNG8 unless a different supported
     745    /// format is requested. An exception will be thrown if an unsupported image
     746    /// format is requested.
     747    ///
     748    /// \exception MgArgumentOutOfRangeException
     749    /// \exception MgInvalidResourceTypeException
     750    /// \exception MgNullArgumentException
     751    /// \exception MgInvalidImageFormatException
     752    ///
     753    /// \since 3.0
     754    MgByteReader* GenerateLegendImage(INT32 width, INT32 height, CREFSTRING format, INT32 geomType, INT32 themeCategory);
     755
     756    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     757    /// \brief
     758    /// Gets the list of geometry type styles for this layer at the map's current scale. Returns NULL if there are no applicable geometry types
     759    ///
     760    /// <!-- Syntax in .Net, Java, and PHP -->
     761    /// \htmlinclude DotNetSyntaxTop.html
     762    /// virtual MgIntCollection GetGeometryTypeStyles(double scale);
     763    /// \htmlinclude SyntaxBottom.html
     764    /// \htmlinclude JavaSyntaxTop.html
     765    /// virtual MgIntCollection GetGeometryTypeStyles(double scale);
     766    /// \htmlinclude SyntaxBottom.html
     767    /// \htmlinclude PHPSyntaxTop.html
     768    /// virtual MgIntCollection GetGeometryTypeStyles(double scale);
     769    /// \htmlinclude SyntaxBottom.html
     770    ///
     771    /// \param scale (double)
     772    /// The scale at which to retrive the list of applicable geometry types
     773    ///
     774    /// \remarks
     775    /// For a scale range with multiple composite styles, multiple instances of (4 = composite) will be in the resulting collection
     776    ///
     777    /// \return
     778    /// The list of geometry type styles for this layer at the map's current scale. Returns NULL if there are no applicable geometry types
     779    ///
     780    /// \since 3.0
     781    MgIntCollection* GetGeometryTypeStyles(double scale);
     782
     783    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     784    /// \brief
     785    /// Gets the number of theme categories for this layer at the map's current scale for the given geometry type style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
     786    ///
     787    /// <!-- Syntax in .Net, Java, and PHP -->
     788    /// \htmlinclude DotNetSyntaxTop.html
     789    /// virtual int GetThemeCategoryCount(double scale, int geomType);
     790    /// \htmlinclude SyntaxBottom.html
     791    /// \htmlinclude JavaSyntaxTop.html
     792    /// virtual int GetThemeCategoryCount(double scale, int geomType);
     793    /// \htmlinclude SyntaxBottom.html
     794    /// \htmlinclude PHPSyntaxTop.html
     795    /// virtual int GetThemeCategoryCount(double scale, int geomType);
     796    /// \htmlinclude SyntaxBottom.html
     797    ///
     798    /// \param scale (double)
     799    /// The scale at which to count the number of applicable theme categories
     800    /// \param geomType (int)
     801    /// The geometry type
     802    ///
     803    /// \remarks
     804    /// When geomType = 4, it will only count the number of the theme categories for the first composite style it finds. For a scale range
     805    /// with multiple composite type styles, you should use GetCompositeThemeCategoryCount() instead
     806    ///
     807    /// \return
     808    /// The number of theme categories for this layer at the map's current scale for the given geometry type style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
     809    ///
     810    /// \since 3.0
     811    INT32 GetThemeCategoryCount(double scale, INT32 geomType);
     812
     813    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     814    /// \brief
     815    /// Gets the number of composite theme categories for this layer at the map's current scale for the given composite style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
     816    ///
     817    /// <!-- Syntax in .Net, Java, and PHP -->
     818    /// \htmlinclude DotNetSyntaxTop.html
     819    /// virtual int GetThemeCategoryCount(double scale, int geomType);
     820    /// \htmlinclude SyntaxBottom.html
     821    /// \htmlinclude JavaSyntaxTop.html
     822    /// virtual int GetThemeCategoryCount(double scale, int geomType);
     823    /// \htmlinclude SyntaxBottom.html
     824    /// \htmlinclude PHPSyntaxTop.html
     825    /// virtual int GetThemeCategoryCount(double scale, int geomType);
     826    /// \htmlinclude SyntaxBottom.html
     827    ///
     828    /// \param scale (double)
     829    /// The scale at which to count the number of applicable theme categories
     830    /// \param compositeOffset (int)
     831    /// The zero-based index denoting the particular composite style to count from. 0 = 1st composite style, 1 = 2nd composite style
     832    ///
     833    /// \return
     834    /// The number of theme categories for this layer at the map's current scale for the given composite style. A count greater than 1 indicates a themed layer. Returns -1 if there are no applicable styles at the current scale
     835    ///
     836    /// \since 3.0
     837    INT32 GetCompositeThemeCategoryCount(double scale, INT32 compositeOffset);
     838
     839    ////////////////////////////////////////////////////////////////////////////////
     840    /// \brief
     841    /// Returns the legend image for the specified geometry type and theme category
     842    ///
     843    /// <!-- Syntax in .Net, Java, and PHP -->
     844    /// \htmlinclude DotNetSyntaxTop.html
     845    /// virtual MgByteReader GenerateLegendImage(double scale, int width, int height, string format, int geomType, int themeCategory);
     846    /// \htmlinclude SyntaxBottom.html
     847    /// \htmlinclude JavaSyntaxTop.html
     848    /// virtual MgByteReader GenerateLegendImage(double scale, int width, int height, String format, int geomType, int themeCategory);
     849    /// \htmlinclude SyntaxBottom.html
     850    /// \htmlinclude PHPSyntaxTop.html
     851    /// virtual MgByteReader GenerateLegendImage(double scale, int width, int height, string format, int geomType, int themeCategory);
     852    /// \htmlinclude SyntaxBottom.html
     853    ///
     854    /// \param resource (MgResourceIdentifier)
     855    /// Input
     856    /// MgResourceIdentifier object identifying the layer definition resource.
     857    /// \param scale (double)
     858    /// Input
     859    /// The scale at which the symbolization is requested.
     860    /// \param width (int)
     861    /// Input
     862    /// The requested image width in pixels.
     863    /// \param height (int)
     864    /// Input
     865    /// The requested image height in pixels.
     866    /// \param format (String/string)
     867    /// Input
     868    /// Image format, from MgImageFormats. Example: PNG, JPG, PNG8, etc
     869    /// \param geomType (int)
     870    /// Input
     871    /// The type of symbolization required: 1=Point, 2=Line, 3=Area, 4=Composite
     872    /// \param themeCategory (int)
     873    /// Input
     874    /// The value indicating which theme category swatch to return.
     875    /// Used when there is a theme defined at this scale. An exception will be
     876    /// thrown if a requested them category doesn't exist.
     877    ///
     878    /// \return
     879    /// Returns a stream representing the legend image.
     880    /// The default returned image format will be PNG8 unless a different supported
     881    /// format is requested. An exception will be thrown if an unsupported image
     882    /// format is requested.
     883    ///
     884    /// \exception MgArgumentOutOfRangeException
     885    /// \exception MgInvalidResourceTypeException
     886    /// \exception MgNullArgumentException
     887    /// \exception MgInvalidImageFormatException
     888    ///
     889    /// \since 3.0
     890    MgByteReader* GenerateLegendImage(double scale, INT32 width, INT32 height, CREFSTRING format, INT32 geomType, INT32 themeCategory);
     891};
     892}}}
     893
     894=== SelectFeatures with transformation ===
     895
     896This RFC will also implement this previously un-implemented API:
     897
     898{{{
     899class MG_PLATFORMBASE_API MgFeatureService : public MgService
     900{
     901PUBLISHED_API:
     902    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     903    /// \brief
     904    /// Selects features from a feature source according to the
     905    /// criteria set in the MgFeatureQueryOptions argument The
     906    /// criteria are applied to all of the features in the feature
     907    /// source. Use the coordinateSystem argument to set the target
     908    /// coordinate system if you want to transform.
     909    /// If you want to apply the criteria to a subset of the
     910    /// features, use MgFeatureService::SelectAggregate.
     911    /// See \link FiltersAndExpressions Filters and expressions \endlink.
     912    ///
     913    /// \remarks
     914    /// Be sure to Close() the MgFeatureReader object returned by this method.
     915    ///
     916    /// <!-- Syntax in .Net, Java, and PHP -->
     917    /// \htmlinclude DotNetSyntaxTop.html
     918    /// virtual MgFeatureReader SelectFeatures(MgResourceIdentifier resource, string className, MgFeatureQueryOptions options, string coordinateSystem);
     919    /// \htmlinclude SyntaxBottom.html
     920    /// \htmlinclude JavaSyntaxTop.html
     921    /// virtual MgFeatureReader SelectFeatures(MgResourceIdentifier resource, String className, MgFeatureQueryOptions options, String coordinateSystem);
     922    /// \htmlinclude SyntaxBottom.html
     923    /// \htmlinclude PHPSyntaxTop.html
     924    /// virtual MgFeatureReader SelectFeatures(MgResourceIdentifier resource, string className, MgFeatureQueryOptions options, string coordinateSystem);
     925    /// \htmlinclude SyntaxBottom.html
     926    ///
     927    /// \param resource (MgResourceIdentifier)
     928    /// A resource identifier for the feature
     929    /// source.
     930    /// \param className (String/string)
     931    /// The name of the feature class from which
     932    /// the properties of interest are selected.
     933    /// \param options (MgFeatureQueryOptions)
     934    /// MgFeatureQueryOptions instance
     935    /// containing all required filters for this
     936    /// select operation.
     937    /// \param coordinateSystem (String/string)
     938    /// The name of the coordinate system to transform to.
     939    ///
     940    /// \return
     941    /// Returns an MgFeatureReader containing the set of selected
     942    /// features.
     943    ///
     944    /// \exception MgFeatureServiceException
     945    /// \exception MgInvalidArgumentException
     946    /// \exception MgFdoException
     947    ///
     948    virtual MgFeatureReader* SelectFeatures(MgResourceIdentifier* resource,
     949                                            CREFSTRING className,
     950                                            MgFeatureQueryOptions* options,
     951                                            CREFSTRING coordinateSystem) = 0;
     952};
     953}}}
     954
     955And we'll include a convenience form of this API in MgLayerBase
     956{{{
     957class MG_PLATFORMBASE_API MgLayerBase : public MgNamedSerializable
     958{
     959PUBLISHED_API:
     960    //////////////////////////////////////////////////////////////////
     961    /// \brief
     962    /// Selects features from a feature source according to the
     963    /// criteria set in the MgFeatureQueryOptions argument The
     964    /// criteria are applied to all of the features in the feature
     965    /// source. If you want to apply the criteria to a subset of the
     966    /// features, use the \link MgFeatureService::SelectAggregate MgFeatureService::SelectAggregate Method \endlink.
     967    /// See \link FiltersAndExpressions Filters and expressions \endlink.
     968    ///
     969    /// <!-- Syntax in .Net, Java, and PHP -->
     970    /// \htmlinclude DotNetSyntaxTop.html
     971    /// virtual MgFeatureReader SelectFeatures(MgFeatureQueryOptions options);
     972    /// \htmlinclude SyntaxBottom.html
     973    /// \htmlinclude JavaSyntaxTop.html
     974    /// virtual MgFeatureReader SelectFeatures(MgFeatureQueryOptions options);
     975    /// \htmlinclude SyntaxBottom.html
     976    /// \htmlinclude PHPSyntaxTop.html
     977    /// virtual MgFeatureReader SelectFeatures(MgFeatureQueryOptions options);
     978    /// \htmlinclude SyntaxBottom.html
     979    ///
     980    /// \param options (MgFeatureQueryOptions)
     981    /// MgFeatureQueryOptions instance
     982    /// containing all required filters for this
     983    /// select operation.
     984    /// \param coordinateSystem (String/string)
     985    /// The coordinate system to transform features to
     986    ///
     987    /// \return
     988    /// Returns an MgFeatureReader containing the set of selected
     989    /// features.
     990    ///
     991    /// \exception MgFeatureServiceException
     992    /// \exception MgInvalidArgumentException
     993    /// \exception MgFdoException
     994    ///
     995    /// \since 3.0
     996    virtual MgFeatureReader* SelectFeatures(MgFeatureQueryOptions* options, CREFSTRING coordinateSystem);
     997};
     998}}}
     999
     1000=== API promotions ===
     1001
     1002This RFC will also promote the following APIs previously marked as INTERNAL_API:
     1003
     1004==== MgResourceService::GetResourceModifiedDate ====
     1005
     1006This API has been promoted to EXTERNAL_API. This method has utility in implementing HTTP caching for representations of a resource. In order to do this, you need to know the date/time a resource was modified to set and/or compare against so that proper cache expiry logic can be applied. This method already provides this information.
     1007
     1008== Implications ==
     1009
     1010As with [wiki:MapGuideRfc9 MapGuide RFC 9], the new convenience APIs in MgLayer/MgLayerBase will only work if the parent MgMap was initialized with an MgSiteConnection instance. If [wiki:MapGuideRfc139 MapGuide RFC 139] is adopted, the deprecated MgMap() constructor will be removed, eliminating the possibility of these APIs not working under certain conditions.
     1011
     1012== Test Plan ==
     1013
     1014Add unit tests that exercise these new convenience APIs
     1015
     1016== Funding / Resources ==
     1017
     1018Community